home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_smalltalk1_2.lha / mstinterp.c < prev    next >
C/C++ Source or Header  |  1992-02-15  |  145KB  |  5,204 lines

  1. /***********************************************************************
  2.  *
  3.  *    Byte Code Interpreter Module.
  4.  *
  5.  *    Interprets the compiled bytecodes of a method.
  6.  *
  7.  ***********************************************************************/
  8.  
  9. /***********************************************************************
  10.  *
  11.  * Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  12.  * Written by Steve Byrne.
  13.  *
  14.  * This file is part of GNU Smalltalk.
  15.  *
  16.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  17.  * under the terms of the GNU General Public License as published by the Free
  18.  * Software Foundation; either version 1, or (at your option) any later 
  19.  * version.
  20.  * 
  21.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  22.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  23.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  24.  * more details.
  25.  * 
  26.  * You should have received a copy of the GNU General Public License along with
  27.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  28.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  29.  *
  30.  ***********************************************************************/
  31.  
  32. /*
  33.  *    Change Log
  34.  * ============================================================================
  35.  * Author      Date       Change
  36.  * sbb         28 Nov 91      Added SystemDictionary byteCodeCounter primitive.
  37.  *
  38.  * sbb          9 Nov 91      Fixed new: to indicate failure when failure occurs.
  39.  *
  40.  * sbb          2 Nov 91      Fixed instVarAt: to obey real stack conventions (was
  41.  *              pushing instead of setting the stack top).
  42.  *
  43.  * sbb          2 Nov 91      Altered the logic in the primitive replace from code
  44.  *              -- I don't think it was really wrong, but it wasn't
  45.  *              as clear as it might have been.
  46.  *
  47.  * sbb         20 Oct 91      Added support for user level control of memory space
  48.  *              growth rate parameters.
  49.  *
  50.  * sbb         15 Sep 91      Added quitPrimitive: to allow for non-zero exit
  51.  *              statuses.
  52.  *
  53.  * sbb          5 Jul 91      Added support for primitive 105, which is the basic
  54.  *              fast support for doing replacement within strings.
  55.  *
  56.  * sbb          5 Jul 91      Added primitive 248:
  57.  *                 FileStream fileInLine: lineNum
  58.  *                            fileName: aString
  59.  *                            at: charPosInt
  60.  *              This helps improve things for the emacs interface by
  61.  *              making recorded information accurate, and making
  62.  *              error locations also be accurate.
  63.  *
  64.  * sbb          2 Jul 91      Fixed handling of jump true and jump false opcodes:
  65.  *              they now issue an error if invoked with non trueOOP
  66.  *              or falseOOP.
  67.  *
  68.  * sbb         19 Apr 91      Added primitive to support conditional compilation.
  69.  *
  70.  * sbb         23 Mar 91      Improved speed another 50% by "inlining" many of the
  71.  *              special selectors that the compiler uses.
  72.  *
  73.  * sbb         23 Mar 91      Fixed a bug with process switching: you can't depend
  74.  *              on objects gotten with oopToObj after a
  75.  *              prepareToStore into the parent object: it may have
  76.  *              moved, and you're storing into dead storage.
  77.  *
  78.  * sbb         17 Mar 91      Added support for C-style interrupts (signals) and
  79.  *              timed interrupts to help with time slicing.
  80.  *
  81.  * sbb         27 Jan 91      Modified the definition of the inline-controlling
  82.  *              macro so that inlining is always selected when
  83.  *              compiling for debugging. 
  84.  *
  85.  * sbb          5 Jan 91      Converted executePrimitiveOperation to do returns as
  86.  *              soon as possible, to not use the failed variable, and
  87.  *              to not do double switching on int and float
  88.  *              operations.  This simple change increased performance
  89.  *              from ~130K bytecodes/sec (SS1+ optim) to > 200k
  90.  *              bytecodes/sec (simple code, builtins and primitives
  91.  *              only, no real method invocation).
  92.  *
  93.  * sbb          1 Jan 91      Switched to not creating MethodContexts always...just
  94.  *              use a cache of pre-made fake method contexts and only
  95.  *              create real method contexts when someone will get a
  96.  *              reference to one of the method contexts.
  97.  *
  98.  * sbb         21 Aug 90      Added support for subtypes of CObject to provide
  99.  *              direct access to C data.
  100.  *
  101.  * sbb          3 Aug 90      Added support for primitive C object allocation
  102.  *              routine.
  103.  *
  104.  * sbyrne    20 May 90      Improved error handling when error: or
  105.  *              doesNotUnderstand: occurs.  Also, added ^C handling
  106.  *              to abort execution.
  107.  *
  108.  * sbyrne    24 Apr 90      Improved error handling for fopen/popen primitives.
  109.  *
  110.  * sbyrne    20 Apr 90      Make fileIn not close the stream that it's reading
  111.  *              from; this is taken care of by the caller, and causes
  112.  *              very strange behavior if we try to close it twice!
  113.  *
  114.  * sbyrne     7 Apr 90      Added declaration tracing primitive.
  115.  *
  116.  * sbyrne     7 Apr 90      Fixed fileIn: to check for existence of the file
  117.  *              before trying to open it.  Returns failure if the
  118.  *              file cannot be accessed.
  119.  *
  120.  * sbyrne    25 Mar 90      Minor change for AtariSt: decrease size of ASYNC
  121.  *              queue size.
  122.  *
  123.  * sbyrne    19 Dec 89      Added suport for primitive filein (for use with
  124.  *              autoload --
  125.  *                              "12 gauge autoloader"
  126.  *                              A. Swartzenegger
  127.  *                              The Terminator)
  128.  *
  129.  * sbyrne     2 Sep 89      Process primitives in and working...starting to
  130.  *              switch to compiled methods with descriptor instance
  131.  *              variable in addition to header.
  132.  *
  133.  * sbyrne     9 Aug 89      Conversion completed.  Performance now 40k
  134.  *              bytecodes/sec; was 43k bytecodes/sec.
  135.  *
  136.  * sbyrne    18 Jul 89      Began conversion from stack based method contexts and
  137.  *              blocks to more traditional method contexts and
  138.  *              blocks.  This change was done 1) to make call in from
  139.  *              C easier, 2) to make processs possible (they could
  140.  *              have been implemented using stack based contexts, but
  141.  *              somewhat space-wastefully), and 3) to conform with
  142.  *              the more traditional definition method contexts and
  143.  *              block contexts.
  144.  *
  145.  * sbyrne    26 May 89      added method cache!  Why didn't I spend the 1/2 hour
  146.  *              sooner?
  147.  *
  148.  * sbyrne     7 Jan 89      Created.
  149.  *
  150.  */
  151.  
  152.  
  153. #include "mst.h"
  154. #include "mstinterp.h"
  155. #include "mstdict.h"
  156. #include "mstsym.h"
  157. #include "mstoop.h"
  158. #include "mstsave.h"
  159. #include "mstcomp.h"
  160. #include "mstcint.h"
  161. #include "mstsysdep.h"
  162. #include "mstlex.h"
  163. #include <math.h>
  164. #include <stdio.h>
  165. #include <signal.h>
  166. #include <sys/types.h>
  167. #include <sys/stat.h>
  168. #include <setjmp.h>
  169.  
  170. #define    METHOD_CACHE_SIZE        (1 << 11) /* 2048, mostly random choice */
  171. #ifdef atarist
  172. #define ASYNC_QUEUE_SIZE        16 /* still way too much */
  173. #else
  174. #define ASYNC_QUEUE_SIZE        100 /* way too much */
  175. #endif
  176.  
  177. /* Max number of C-style signals on a machine */
  178. #define NUM_SIGNALS    32
  179.  
  180. /* Don't enable this...it doesn't really work properly with the new GC, since
  181.    using local register variables defeats the ability to copy the root set
  182.    when a GC flip occurs. */
  183. #define LOCAL_REGS /* Enabled experimentally 29-Dec-91 18:00:04 */
  184.  
  185. /* Enabling this means that some accessors for method object pieces, such
  186.    as instance variables or literals, are implemented as routines, instead
  187.    of being in-line code via macros */
  188. /* #define ACCESSOR_DEBUGGING */
  189.  
  190. #if defined(OPTIMIZE) && defined(ACCESSOR_DEBUGGING)
  191. /* Turn this off when we're optimizing. */
  192. #undef ACCESSOR_DEBUGGING
  193. #endif
  194.  
  195. #ifdef LOCAL_REGS
  196. #define exportSP()    *spAddr = sp
  197. #define exportIP()    *ipAddr = ip
  198. #define exportRegs()    { exportSP(); exportIP(); }
  199. #define importSP()    sp = *spAddr
  200. #define importIP()    ip = *ipAddr
  201. #define importRegs()    { importSP(); importIP(); }
  202. #else
  203. #define exportSP()
  204. #define exportIP()
  205. #define exportRegs()
  206. #define importSP()
  207. #define importIP()
  208. #define importRegs()
  209. #endif /* LOCAL_REGS */
  210.  
  211. #ifndef ACCESSOR_DEBUGGING
  212.  
  213. #ifdef OPTIMIZE
  214. #define receiverVariableInternal(receiver, index) \
  215.   (oopToObj(receiver)->data[index])
  216. #else
  217. #define receiverVariableInternal(receiver, index) \
  218.   (!inBounds(receiver, index) && errorf("Index out of bounds %d", index), \
  219.     oopToObj(receiver)->data[index])
  220. #endif /* OPTIMIZE */
  221.  
  222.  
  223. #define getStackReceiverInternal(numArgs) \
  224.   (stackAt(numArgs))
  225.  
  226. #define methodTemporaryInternal(index) \
  227.   (temporaries[index])
  228.  
  229.  
  230. #define methodLiteralInternal(methodOOP, index) \
  231.   (((Method)oopToObj(methodOOP))->literals[index])
  232.  
  233. #define methodVariableInternal(methodOOP, index) \
  234.   (associationValue(((Method)oopToObj(methodOOP))->literals[index]))
  235.  
  236. #define getMethodByteCodesInternal(methodOOP) \
  237.   (isNil(methodOOP) ? (Byte *)nil \
  238.    : ((Byte *)&((Method)oopToObj(methodOOP))->literals[((Method)oopToObj(methodOOP))->header.numLiterals]))
  239.  
  240.  
  241. #define getMethodHeaderInternal(methodOOP) \
  242.   (((Method)oopToObj(methodOOP))->header)
  243.  
  244. #define getMethodClassInternal(methodOOP) \
  245.   (associationValue(((Method)oopToObj(methodOOP))->literals[((Method)oopToObj(methodOOP))->header.numLiterals - 1]))
  246.  
  247.  
  248. #ifdef OPTIMIZE
  249. #define storeReceiverVariableInternal(receiver, index, oop) \
  250. {  \
  251.   OOP __storeRecVarOOP = (oop); \
  252.   prepareToStore(receiver, __storeRecVarOOP); \
  253.   oopToObj(receiver)->data[index] = __storeRecVarOOP; \
  254. }
  255. #else
  256. #define storeReceiverVariableInternal(receiver, index, oop) \
  257. {  \
  258.   OOP __storeRecVarOOP = (oop); \
  259.   if (!inBounds(receiver, index)) { \
  260.     errorf("Index out of bounds %d", index); \
  261.   } \
  262.   prepareToStore(receiver, __storeRecVarOOP); \
  263.   oopToObj(receiver)->data[index] = __storeRecVarOOP; \
  264. }
  265. #endif /* OPTIMIZE */
  266.  
  267.  
  268. #define storeMethodTemporaryInternal(index, oop) \
  269. { \
  270.   OOP __storeMethTempOOP = (oop); \
  271.   prepareToStore(thisContextOOP, __storeMethTempOOP); \
  272.   temporaries[index] = __storeMethTempOOP; \
  273. }
  274.  
  275. #define storeMethodVariableInternal(methodOOP, index, oop) \
  276.   setAssociationValue(((Method)oopToObj(methodOOP))->literals[index], oop)
  277.  
  278. #define storeMethodLiteralInternal(methodOOP, index, oop) \
  279. { \
  280.   OOP __storeMethLitOOP = (oop); \
  281.   prepareToStore(methodOOP, __storeMethLitOOP); \
  282.   ((Method)oopToObj(methodOOP))->literals[index] = __storeMethLitOOP; \
  283. }
  284.  
  285. #ifdef OPTIMIZE
  286. #define inBoundsInternal(oop, index) true
  287. #else /* Not optimize */
  288. #define inBoundsInternal(oop, index) \
  289.   ((index) >= 0 && (index) < numOOPs(oopToObj(oop)))
  290. #endif
  291.  
  292. #define isBlockContextInternal(contextOOP) \
  293.   (oopClass(contextOOP) == blockContextClass)
  294.  
  295. #define relativeByteIndexInternal(bp, methodOOP) \
  296.   ((bp) - getMethodByteCodes(methodOOP))
  297.  
  298. #define getMethodContextInternal(contextOOP) \
  299.   ( (isBlockContext(contextOOP)) \
  300.     ? ((BlockContext)oopToObj(contextOOP))->home \
  301.     : (contextOOP) )
  302.  
  303. #define receiverVariable        receiverVariableInternal
  304. #define getStackReceiver        getStackReceiverInternal
  305. #define methodTemporary            methodTemporaryInternal
  306. #define methodVariable            methodVariableInternal
  307. #define getMethodByteCodes        getMethodByteCodesInternal
  308. #define getMethodClass            getMethodClassInternal
  309. #define storeReceiverVariable        storeReceiverVariableInternal
  310. #define storeMethodTemporary        storeMethodTemporaryInternal
  311. #define storeMethodVariable        storeMethodVariableInternal
  312. #define inBounds            inBoundsInternal
  313. #define isBlockContext            isBlockContextInternal
  314.  
  315. #define methodLiteral            methodLiteralInternal
  316. #define getMethodHeader            getMethodHeaderInternal
  317. #define storeMethodLiteral        storeMethodLiteralInternal
  318. /*
  319.    #define relativeByteIndex        relativeByteIndexInternal
  320. */
  321. #define getMethodContext        getMethodContextInternal
  322. #endif /* !ACCESSOR_DEBUGGING */
  323.  
  324.  
  325. /* Ordering of file operations must match that used in FileSegment.st */
  326. typedef enum {
  327.   openFilePrim,
  328.   closeFilePrim,
  329.   getCharPrim,
  330.   putCharPrim,
  331.   seekPrim,
  332.   tellPrim,
  333.   eofPrim,
  334.   popenFilePrim,
  335.   sizePrim,
  336.   putCharsPrim,
  337.   getCharsPrim
  338. } filePrimitiveTypes;
  339.  
  340. typedef struct FileStreamStruct {
  341.   OBJ_HEADER;
  342.   OOP        collection;
  343.   OOP        ptr;
  344.   OOP        endPtr;
  345.   OOP        access;
  346.   OOP        maxSize;
  347.   OOP        file;
  348.   OOP        name;
  349. } *FileStream;
  350.  
  351. typedef struct CompiledMethodStruct *Method;
  352.  
  353. typedef struct MethodContextStruct {
  354.   OBJ_HEADER;
  355.   OOP        sender;
  356.   OOP        ipOffset;    /* an integer byte index into method */
  357.   OOP        spOffset;    /* an integer index into cur context stack */
  358.   OOP        method;        /* the method that we're executing */
  359.   OOP        methodClass;    /* the class of the method that's executing */
  360.   OOP        hasBlock;    /* nil or not nil */
  361.   OOP        selector;    /* the selector that invoked this method */
  362.   OOP        receiver;    /* the Receiver OOP */
  363.   OOP        contextStack[CONTEXT_STACK_SIZE];
  364. } *MethodContext;
  365.  
  366. typedef struct BlockContextStruct {
  367.   OBJ_HEADER;
  368.   OOP        caller;
  369.   OOP        ipOffset;    /* an integer byte index into method */
  370.   OOP        spOffset;    /* an integer index into cur context stack */
  371.   OOP        numArgs;    /* number of arguments we have */
  372.   OOP        methodClass;    /* placeholder; not used */
  373.   OOP        initialIP;    /* initial value of IP (an offset) */
  374.   OOP        selector;    /* the selector that invoked this block */
  375.   OOP        home;        /* the home context */
  376.   OOP        contextStack[CONTEXT_STACK_SIZE];
  377. } *BlockContext;
  378.  
  379. typedef struct FakeContextOOP {
  380.   struct MethodContextStruct mc;
  381.   struct OOPStruct oop;
  382. } *FakeOOP;
  383.  
  384. typedef struct SemaphoreStruct {
  385.   OBJ_HEADER;
  386.   OOP        firstLink;
  387.   OOP        lastLink;
  388.   OOP        signals;
  389. } *Semaphore;
  390.  
  391. typedef struct ProcessStruct {
  392.   OBJ_HEADER;
  393.   OOP        nextLink;
  394.   OOP        suspendedContext;
  395.   OOP        priority;
  396.   OOP        myList;
  397. } *Process;
  398.  
  399. typedef struct ProcessorSchedulerStruct {
  400.   OBJ_HEADER;
  401.   OOP        processLists;
  402.   OOP        activeProcess;
  403. } *ProcessorScheduler;
  404.  
  405. long methodCount = 0, totalMethods = 0;
  406.  
  407.  
  408. long            byteCodeCounter;
  409. long            cacheHits = 0;
  410. long            cacheMisses = 0;
  411.  
  412. /* !!! */
  413. Boolean            gcDebug = false;
  414.  
  415. /* If this is true, for each byte code that is executed, the byte index
  416.  * within the current CompiledMethod and a decoded interpretation of
  417.  * the byte code is printed on standard output. */
  418. Boolean            executionTracing;
  419.  
  420. /* When this is true, and an interrupt occurs (such as SIGSEGV), Smalltalk
  421.  * will terminate itself by making a core dump (normally it does not
  422.  * terminate in this manner). */
  423. Boolean            makeCoreFile = false;
  424.  
  425.  
  426. Byte            *ip, **ipAddr = &ip;
  427. OOP            *sp, **spAddr = &sp;
  428. OOP            thisMethod;
  429.  
  430. int            collide[METHOD_CACHE_SIZE];
  431.  
  432. #ifdef countingByteCodes
  433. static long        byteCodes[256];
  434. static long        primitives[256];
  435. #endif
  436.  
  437. static OOP        methodCacheSelectors    [METHOD_CACHE_SIZE];
  438. static OOP        primitiveCacheSelectors [METHOD_CACHE_SIZE];
  439. static OOP        methodCacheClasses      [METHOD_CACHE_SIZE];
  440. static OOP        primitiveCacheClasses   [METHOD_CACHE_SIZE];
  441. static OOP        methodCacheMethods      [METHOD_CACHE_SIZE];
  442. static int        primitiveCachePrimitives[METHOD_CACHE_SIZE];
  443. static OOP        methodCacheMethodClasses[METHOD_CACHE_SIZE];
  444.  
  445. static OOP        queuedAsyncSignals    [ASYNC_QUEUE_SIZE]; 
  446. static int        asyncQueueIndex;
  447. static OOP        switchToProcess; /* non-nil when proc switch wanted */
  448.  
  449. static OOP        *temporaries;    /* points into method or block context
  450.                      * to start of arguments and
  451.                      * temporaries */
  452. static OOP        self;
  453. static OOP        thisContextOOP;
  454. static Boolean        inInterpreter = false;
  455. static int        exceptFlag;
  456.  
  457. /* Holds the semaphore to signal when the processor interval timesout */
  458. static OOP        timeoutSem;
  459.  
  460. static OOP        semIntVec[NUM_SIGNALS];
  461. static Boolean        semIntHappened[NUM_SIGNALS];
  462. static Boolean        semIntFlag = false;
  463.  
  464.  
  465. /* When true, this causes the byte code interpeter to immediately act
  466.  * as if it saw a stream af method return bytecodes, until it finally exits.
  467.  */
  468. static Boolean        abortExecution = false;
  469.  
  470. /* When this is true, it means that the system is executing external C code,
  471.  * which can be used by the ^C handler to know whether it longjmp to the
  472.  * end of the C callout primitive in executePrimitiveOperation. */
  473. static Boolean        inCCode = false;
  474.  
  475.  
  476. /* Used to handle the case when the user types a ^C while executing callout
  477.  * code */
  478. static jmp_buf cCalloutJmpBuf;
  479.  
  480. /* when this flag is on and execution tracing is in effect, the top
  481.  * of the stack is printed as well as the byte code */
  482. static Boolean        verboseExecTracing = false;
  483.  
  484. /* when true, this tells the iterpreter that the processor timer has gone off,
  485.  * and that it should set the timeout semaphore */
  486. static Boolean        signalTimeoutSemaphore = false;
  487.  
  488.  
  489. #ifdef ACCESSOR_DEBUGGING
  490. static OOP        methodTemporary(), receiverVariable(),
  491.               methodVariable(), getMethodClass(),
  492.             getStackReceiver(), methodLiteral(),
  493.             getMethodContext();
  494. static void        storeMethodTemporary(), storeReceiverVariable(),
  495.               storeMethodVariable(), storeMethodLiteral();
  496. static Boolean        inBounds(), isBlockContext();
  497. static Byte        *getMethodByteCodes();
  498. static MethodHeader    getMethodHeader();
  499. #endif /* ACCESSOR_DEBUGGING */
  500. static int        relativeByteIndex();
  501. static OOP        findMethod(), createMethodContext(), 
  502.             getActiveProcess(),
  503.             getProcessLists(), highestPriorityProcess(),
  504.             removeFirstLink(), semaphoreNew(),
  505.               realizeContext();
  506. static void        returnWithValue(), 
  507.             sendBlockValue(),
  508.             showBacktrace(),
  509.             invalidateMethodCache(), methodHasBlockContext(),
  510.             sleepProcess(), resumeProcess(), activateProcess(),
  511.             changeProcessContext(), addLastLink(),
  512.             suspendActiveProcess(), moveSemaphoreOOPs(),
  513.             copyFakeContextObjects();
  514.  
  515. static Boolean        executePrimitiveOperation(),
  516.             noParentContext(), isEmpty(), isRealOOP(),
  517.             *boolAddrIndex();
  518.  
  519. static char        *selectorAsString();
  520. static signalType    interruptHandler(), stopExecuting(), timeoutHandler(),
  521.             semIntHandler();
  522.  
  523. #ifdef old_code /* Sat Jan 19 14:42:06 1991 */
  524. /**/static OOP        *mathSelectors[16] = {
  525. /**/  &plusSymbol,            /* 0  + */
  526. /**/  &minusSymbol,            /* 1  - */
  527. /**/  &lessThanSymbol,        /* 2  < */
  528. /**/  &greaterThanSymbol,        /* 3  > */
  529. /**/  &lessEqualSymbol,        /* 4  <= */
  530. /**/  &greaterEqualSymbol,        /* 5  >= */
  531. /**/  &equalSymbol,            /* 6  = */
  532. /**/  ¬EqualSymbol,        /* 7  ~= */
  533. /**/  ×Symbol,            /* 8  * */
  534. /**/  ÷Symbol,        /* 9  / */
  535. /**/  &remainderSymbol,        /* 10 \\ */
  536. /**/  &plusSymbol,            /* 11 @, not implemented */
  537. /**/  &bitShiftColonSymbol,        /* 12 bitShift: */
  538. /**/  &integerDivideSymbol,        /* 13 // */
  539. /**/  &bitAndColonSymbol,        /* 14 bitAnd: */
  540. /**/  &bitOrColonSymbol        /* 15 bitOr: */
  541. /**/};
  542. #endif /* old_code Sat Jan 19 14:42:06 1991 */
  543.  
  544. struct SpecialSelectorStruct {
  545.   OOP        *selector;
  546.   int        args;
  547. } specialMessages[16] = {
  548.   &atColonSymbol,        1,
  549.   &atColonPutColonSymbol,    2,
  550.   &sizeSymbol,            0,
  551.   &nextSymbol,            0,
  552.   &nextPutColonSymbol,        1,
  553.   &atEndSymbol,            0,
  554.   &sameObjectSymbol,        1,
  555.   &classSymbol,            0,
  556.   &blockCopyColonSymbol,    1,
  557.   &valueSymbol,            0,
  558.   &valueColonSymbol,        1,
  559.   &doColonSymbol,        1,
  560.   &newSymbol,            0,
  561.   &newColonSymbol,        1,
  562.   &nilSymbol,            0, /* unimplemented selector */
  563.   &nilSymbol,            0  /* unimplemented selector */
  564. };
  565.  
  566. /*
  567.  
  568. ### This is from the old stack based context days...update it to reflect
  569. reality!
  570.  
  571. +-----------------------------------+
  572. | receiver (self)            |
  573. +-----------------------------------+
  574. | args                    |
  575. +-----------------------------------+
  576. | ...                    |
  577. +-----------------------------------+
  578. | temps                    |
  579. +-----------------------------------+
  580. | ...                    |
  581. +-----------------------------------+
  582. | saved ip of caller (relative)        | FP, SP on interpreter entry
  583. +-----------------------------------+
  584. | saved method of caller            |
  585. +-----------------------------------+
  586. | saved temp pointer of caller        |
  587. +-----------------------------------+
  588. | saved frame pointer of caller (?) |
  589. +-----------------------------------+
  590. | isBlock (boolean)                 |
  591. +-----------------------------------+
  592. | method context pointer        |
  593. +-----------------------------------+
  594. |                                   | SP (after saving state)
  595.  
  596.  */
  597.  
  598.  
  599. /*
  600.  Interpretation of the virtual machine byte codes
  601.  
  602. 0-15 push receiver variable     0000iiii
  603. 16-31 push temporary location    0001iiii
  604. 32-63 push literal constant    001iiiii
  605. 64-95 push literal variable    010iiiii
  606. 96-103 pop & store rec var    01100iii
  607. 104-111 pop & store temp loc    01101iii
  608. 112-119 push indexed        01110iii receiver true false nil -1 0 1 2
  609. 120-123 return indexed        011110ii receiver true false nil
  610. 124-125 return st top from    0111110i message, block
  611. 126-127 unused            0111111i
  612. 128    push indir        10000000 jjkkkkkk (receiver var, temp loc,
  613.                            lit const, lit var)
  614.                            [jj] #kkkkkk
  615. 129    store indir        10000001 jjkkkkkk (rv, tl, illegal, lv)
  616. 130    pop & store indir    10000010 jjkkkkkk (like store indir)
  617. 131    send lit selector    10000011 jjjkkkkk sel #kkkkk with jjj args
  618. 132    send lit selector    10000100 jjjjjjjj kkkkkkkk (as 131)
  619. 133    send lit sel to super    10000101 jjjkkkkk as 131
  620. 134    send lit to super    10000110 jjjjjjjj kkkkkkkk like 132
  621. 135    pop stack top        10000111
  622. 136    duplicate stack top    10001000
  623. 137    push active context    10001001
  624. 138-143    unused
  625. 144-151    jmp iii+1        10010iii
  626. 152-159    pop & jmp false iii+1    10011iii
  627. 160-167    jmp (iii-4)*256+jjjjjjjj10100iii jjjjjjjj
  628. 168-171 pop & jmp on true    101010ii jjjjjjjj ii*256+jjjjjjjj
  629. 172-175 pop & jmp on false    101011ii jjjjjjjj like 168
  630. 176-191 send arith message    1011iiii
  631. 192-207    send special message    1100iiii
  632. 208-223 send lit sel #iiii    1101iiii with no arguments
  633. 224-239 send lit sel #iiii    1110iiii with 1 argument
  634. 240-255 send lit sel #iiii    1111iiii with 2 arguments
  635. */
  636.  
  637. /*
  638.  *
  639.  * How the interpreter works:
  640.  *  1) The interpreter expects to be called in an environment where there
  641.  *     already exists a well-defined method context.  The instruction pointer,
  642.  *     stored in the global variable "ip", and the stack pointer, stored in the
  643.  *     global variable "sp", should be set up to point into the current
  644.  *     method and MethodContext.  Other global variables, such as "thisMethod",
  645.  *     "self", "temporaries", etc. should also be setup.  See the routine
  646.  *     prepareExecutionEnvironment for details.
  647.  *  2) The interpreter checks to see if any change in its state is required,
  648.  *     such as switching to a new process, dealing with an asynchronous signal
  649.  *     which is not yet implemented, and printing out the byte codes that are 
  650.  *     being executed, if that was requested by the user.
  651.  *  3) After that, the byte code that ip points to is fetched and decoded.
  652.  *     Some byte codes perform jumps, which are performed by merely adjusting
  653.  *     the value of ip.  Some are message sends, which are described in
  654.  *     more detail below.  Some instructions require more than one byte code
  655.  *     to perform their work; ip is advanced as needed and the extension
  656.  *     byte codes are fetched.
  657.  *  4) After dispatching the byte code, the interpreter loops around to
  658.  *     execute another byte code.  If ip has changed to point to nil, it is
  659.  *     a signal that the execution of the method is over, and the interpreter
  660.  *     returns to its caller.
  661.  *
  662.  * Note that the interpreter is not called recursively to implement message
  663.  * sends.  Rather the state of the interpreter is saved away in the currently
  664.  * executing context, and a new context is created and the global variables
  665.  * such as ip, sp, and temporaries are initialized accordingly.
  666.  *
  667.  * When a message send occurs, the sendMessage routine is invoked.  It 
  668.  * determines the class of the receiver, and checks to see if it already has
  669.  * cached the method definition for the given selector and receiver class.
  670.  * If so, that method is used, and if not, the receiver's method dictionary
  671.  * is searched for a method with the proper selector.  If it's not found in
  672.  * that method dictionary, the method dictionary of the classes parent is
  673.  * examined, and on up the hierarchy, until a matching selector is found.
  674.  *
  675.  * If no selector is found, the receiver is sent a #doesNotUnderstand: message
  676.  * to indicate that a matching method could not be found.
  677.  *
  678.  * If a method is found, it is examined for some special cases.  The special
  679.  * cases are primitive return of self, return of an instance variable, or
  680.  * execution of a primitive method definition.  This latter operation is
  681.  * performed by the executePrimitiveOperation routine.  If the execution
  682.  * of this primitive interpreter fails, the normal message send operation
  683.  * is performed.
  684.  *
  685.  * If the found method is not one of the special cases, or if it is a 
  686.  * primitive that failed to execute, a "normal" message send is performed.
  687.  * This basically entails saving away what state the interpreter has, such
  688.  * as the values of ip, and sp, being careful to save their relative locations
  689.  * and not their physical addresses, because one or more garbage collections
  690.  * could occur before the method context is returned to, and the absolute
  691.  * pointers would be invalid.
  692.  *
  693.  * The sendMessage routine then creates a new MethodContext object, makes
  694.  * its parent be the currently executing MethodContext, and sets up
  695.  * the interpreters global variables to reference the new method and
  696.  * new MethodContext.  Once those variables are set, sendMessage returns
  697.  * to the interpreter, which cheerfully begins executing the new method,
  698.  * totally unaware that the method that it was executing has changed.
  699.  *
  700.  * When a method returns, the method that called it is used to restore the
  701.  * interpreter's global variables to the state that they were in before
  702.  * the called method was called.  The values of ip and sp are restored to
  703.  * their absolute address values, and the other global state variables
  704.  * are restored accordingly.  When after the state has been restored, the
  705.  * interpreter continues execution, again totally oblivious to the fact
  706.  * that it's not running the same method it was on its previous byte code.
  707.  *
  708.  * Global state
  709.  * The following variables constitute the interpreter's state:
  710.  * ip -- the real memory address of the next byte code to be executed.
  711.  * sp -- the real memory address of the stack that's stored in the currently
  712.  *       executing block or method context.
  713.  * thisMethod -- a CompiledMethod that is the currently executing method.
  714.  * thisContextOOP -- a BlockContext or MethodContext that indicates the
  715.  *                   context that the interpreter is currently running in.
  716.  * temporaries -- physical address of the base of the method temporary
  717.  *                variables.  Typically a small number of bytes (multiple of 4
  718.  *                since it points to OOPs) lower than sp.
  719.  * self -- an OOP that is the current receiver of the current message.
  720.  * 
  721.  * Note about the interpreter:
  722.  * As an experiment, I unrolled the case statement somewhat into separate
  723.  * case arms for each byte code.  The intention was to increase performance.
  724.  * I haven't measured to see whether it makes a difference or not.
  725.  *
  726.  * The local regs concept was pre-GC.  By caching the values of IP and SP
  727.  * in local register variables, I hoped to increase performance.  I only
  728.  * needed to export the variables when I was calling out to routines that
  729.  * might change them.  However, the garbage collector may run at any time,
  730.  * and the values of IP and SP point to things in the root set and so will
  731.  * change on a GC flip.  I'm leaving the code to deal with them as local 
  732.  * registers in but conditionally compiled out until I can figure out a
  733.  * clever way to make them be registers again, or give up on the idea totally.
  734.  */
  735.  
  736. void interpret()
  737. {
  738.   Byte        ival, ival2, ival3, *savedIP;
  739.   OOP        returnedValue, *savedSP, methodContextOOP, tempOOP;
  740.   BlockContext    blockContext;
  741.   int        i;
  742.   IntState    oldSigMask;
  743. #ifdef LOCAL_REGS
  744.   register OOP    *sp;
  745.   register Byte    *ip;
  746. #endif /* LOCAL_REGS */
  747.  
  748.   importRegs();
  749.  
  750.   inInterpreter = true;
  751.  
  752.   exceptFlag = executionTracing;
  753.  
  754.   for (; ip; ) {        /* when IP is nil, return to caller */
  755.     clearGCFlipFlags();
  756.  
  757.     if (exceptFlag) {
  758.       exportRegs();
  759.       if (abortExecution) {
  760.     goto abortMethod;    /* ugh! */
  761.       }
  762.       if (signalTimeoutSemaphore) {
  763.     oldSigMask = disableInterrupts();
  764.     if (isClass(timeoutSem, semaphoreClass)) {
  765.       syncSignal(timeoutSem);
  766.     }
  767.     timeoutSem = nilOOP;
  768.     signalTimeoutSemaphore = false;
  769.     enableInterrupts(oldSigMask);
  770.       }
  771.       if (semIntFlag) {
  772.     oldSigMask = disableInterrupts();
  773.     for (i = 0; i < NUM_SIGNALS; i++) {
  774.       if (semIntHappened[i]) {
  775.         if (isClass(semIntVec[i], semaphoreClass)) {
  776.           syncSignal(semIntVec[i]);
  777.         } else {
  778.           errorf("C signal trapped, but no semaphore was waiting");
  779.         }
  780.         semIntHappened[i] = false;
  781.       }
  782.     }
  783.     semIntFlag = false;
  784.     enableInterrupts(oldSigMask);
  785.       }
  786.  
  787.       if (asyncQueueIndex) {    /* deal with any async signals  */
  788.     oldSigMask = disableInterrupts(); /* block out everything! */
  789.     for (i = 0; i < asyncQueueIndex; i++) {
  790.       /* ### this is not right...async signals must not allocate storage */
  791.       errorf("### Fix asyncSignal handling");
  792.       syncSignal(queuedAsyncSignals[i]);
  793.     }
  794.     asyncQueueIndex = 0;
  795.     enableInterrupts(oldSigMask);
  796.       }
  797.       if (!isNil(switchToProcess)) {
  798.     /*exportRegs(); */
  799.     changeProcessContext(switchToProcess);
  800.     importRegs();
  801.     /* make sure to validate the IP again */
  802.     continue;
  803.       }
  804.       if (executionTracing) {
  805.     printf("%5d:\t", relativeByteIndex(ip, thisMethod));
  806.     printByteCodeName(ip, relativeByteIndex(ip, thisMethod),
  807.               ((Method)oopToObj(thisMethod))->literals);
  808.     printf("\n");
  809.     if (verboseExecTracing) {
  810.       printf("\t  --> ");
  811.       printObject(stackTop());
  812.       printf("\n");
  813.     }
  814.       }
  815.       exceptFlag = executionTracing;
  816.       importRegs();
  817.     }
  818.       
  819.  
  820.     byteCodeCounter++;
  821. #ifdef countingByteCodes
  822.     byteCodes[*ip]++;
  823. #endif /* countingByteCodes */
  824.  
  825.     /* Note: some of the case arms are expanded out to literal cases,
  826.        instead of case0: case1: ... pushOOP(receiverVariable(self, ival&15))
  827.        this is an experiment to try to improve performance of the byte code
  828.        interpreter throughout the system. */
  829.     switch(ival = *ip++) {
  830.     case  0:    pushOOP(receiverVariable(self, 0));    break;
  831.     case  1:    pushOOP(receiverVariable(self, 1));    break;
  832.     case  2:    pushOOP(receiverVariable(self, 2));    break;
  833.     case  3:    pushOOP(receiverVariable(self, 3));    break;
  834.     case  4:    pushOOP(receiverVariable(self, 4));    break;
  835.     case  5:    pushOOP(receiverVariable(self, 5));    break;
  836.     case  6:    pushOOP(receiverVariable(self, 6));    break;
  837.     case  7:    pushOOP(receiverVariable(self, 7));    break;
  838.     case  8:    pushOOP(receiverVariable(self, 8));    break;
  839.     case  9:    pushOOP(receiverVariable(self, 9));    break;
  840.     case 10:    pushOOP(receiverVariable(self, 10));    break;
  841.     case 11:    pushOOP(receiverVariable(self, 11));    break;
  842.     case 12:    pushOOP(receiverVariable(self, 12));    break;
  843.     case 13:    pushOOP(receiverVariable(self, 13));    break;
  844.     case 14:    pushOOP(receiverVariable(self, 14));    break;
  845.     case 15:    pushOOP(receiverVariable(self, 15));    break;
  846.  
  847.     case 16:    pushOOP(methodTemporary(0));    break;
  848.     case 17:    pushOOP(methodTemporary(1));    break;
  849.     case 18:    pushOOP(methodTemporary(2));    break;
  850.     case 19:    pushOOP(methodTemporary(3));    break;
  851.     case 20:    pushOOP(methodTemporary(4));    break;
  852.     case 21:    pushOOP(methodTemporary(5));    break;
  853.     case 22:    pushOOP(methodTemporary(6));    break;
  854.     case 23:    pushOOP(methodTemporary(7));    break;
  855.     case 24:    pushOOP(methodTemporary(8));    break;
  856.     case 25:    pushOOP(methodTemporary(9));    break;
  857.     case 26:    pushOOP(methodTemporary(10));    break;
  858.     case 27:    pushOOP(methodTemporary(11));    break;
  859.     case 28:    pushOOP(methodTemporary(12));    break;
  860.     case 29:    pushOOP(methodTemporary(13));    break;
  861.     case 30:    pushOOP(methodTemporary(14));    break;
  862.     case 31:    pushOOP(methodTemporary(15));    break;
  863.  
  864.     case 32:    pushOOP(methodLiteral(thisMethod, 0));    break;
  865.     case 33:    pushOOP(methodLiteral(thisMethod, 1));    break;
  866.     case 34:    pushOOP(methodLiteral(thisMethod, 2));    break;
  867.     case 35:    pushOOP(methodLiteral(thisMethod, 3));    break;
  868.     case 36:    pushOOP(methodLiteral(thisMethod, 4));    break;
  869.     case 37:    pushOOP(methodLiteral(thisMethod, 5));    break;
  870.     case 38:    pushOOP(methodLiteral(thisMethod, 6));    break;
  871.     case 39:    pushOOP(methodLiteral(thisMethod, 7));    break;
  872.     case 40:    pushOOP(methodLiteral(thisMethod, 8));    break;
  873.     case 41:    pushOOP(methodLiteral(thisMethod, 9));    break;
  874.     case 42:    pushOOP(methodLiteral(thisMethod, 10));    break;
  875.     case 43:    pushOOP(methodLiteral(thisMethod, 11));    break;
  876.     case 44:    pushOOP(methodLiteral(thisMethod, 12));    break;
  877.     case 45:    pushOOP(methodLiteral(thisMethod, 13));    break;
  878.     case 46:    pushOOP(methodLiteral(thisMethod, 14));    break;
  879.     case 47:    pushOOP(methodLiteral(thisMethod, 15));    break;
  880.     case 48:    pushOOP(methodLiteral(thisMethod, 16));    break;
  881.     case 49:    pushOOP(methodLiteral(thisMethod, 17));    break;
  882.     case 50:    pushOOP(methodLiteral(thisMethod, 18));    break;
  883.     case 51:    pushOOP(methodLiteral(thisMethod, 19));    break;
  884.     case 52:    pushOOP(methodLiteral(thisMethod, 20));    break;
  885.     case 53:    pushOOP(methodLiteral(thisMethod, 21));    break;
  886.     case 54:    pushOOP(methodLiteral(thisMethod, 22));    break;
  887.     case 55:    pushOOP(methodLiteral(thisMethod, 23));    break;
  888.     case 56:    pushOOP(methodLiteral(thisMethod, 24));    break;
  889.     case 57:    pushOOP(methodLiteral(thisMethod, 25));    break;
  890.     case 58:    pushOOP(methodLiteral(thisMethod, 26));    break;
  891.     case 59:    pushOOP(methodLiteral(thisMethod, 27));    break;
  892.     case 60:    pushOOP(methodLiteral(thisMethod, 28));    break;
  893.     case 61:    pushOOP(methodLiteral(thisMethod, 29));    break;
  894.     case 62:    pushOOP(methodLiteral(thisMethod, 30));    break;
  895.     case 63:    pushOOP(methodLiteral(thisMethod, 31));    break;
  896.  
  897.     case 64:    pushOOP(methodVariable(thisMethod, 0));    break;
  898.     case 65:    pushOOP(methodVariable(thisMethod, 1));    break;
  899.     case 66:    pushOOP(methodVariable(thisMethod, 2));    break;
  900.     case 67:    pushOOP(methodVariable(thisMethod, 3));    break;
  901.     case 68:    pushOOP(methodVariable(thisMethod, 4));    break;
  902.     case 69:    pushOOP(methodVariable(thisMethod, 5));    break;
  903.     case 70:    pushOOP(methodVariable(thisMethod, 6));    break;
  904.     case 71:    pushOOP(methodVariable(thisMethod, 7));    break;
  905.     case 72:    pushOOP(methodVariable(thisMethod, 8));    break;
  906.     case 73:    pushOOP(methodVariable(thisMethod, 9));    break;
  907.     case 74:    pushOOP(methodVariable(thisMethod, 10));    break;
  908.     case 75:    pushOOP(methodVariable(thisMethod, 11));    break;
  909.     case 76:    pushOOP(methodVariable(thisMethod, 12));    break;
  910.     case 77:    pushOOP(methodVariable(thisMethod, 13));    break;
  911.     case 78:    pushOOP(methodVariable(thisMethod, 14));    break;
  912.     case 79:    pushOOP(methodVariable(thisMethod, 15));    break;
  913.     case 80:    pushOOP(methodVariable(thisMethod, 16));    break;
  914.     case 81:    pushOOP(methodVariable(thisMethod, 17));    break;
  915.     case 82:    pushOOP(methodVariable(thisMethod, 18));    break;
  916.     case 83:    pushOOP(methodVariable(thisMethod, 19));    break;
  917.     case 84:    pushOOP(methodVariable(thisMethod, 20));    break;
  918.     case 85:    pushOOP(methodVariable(thisMethod, 21));    break;
  919.     case 86:    pushOOP(methodVariable(thisMethod, 22));    break;
  920.     case 87:    pushOOP(methodVariable(thisMethod, 23));    break;
  921.     case 88:    pushOOP(methodVariable(thisMethod, 24));    break;
  922.     case 89:    pushOOP(methodVariable(thisMethod, 25));    break;
  923.     case 90:    pushOOP(methodVariable(thisMethod, 26));    break;
  924.     case 91:    pushOOP(methodVariable(thisMethod, 27));    break;
  925.     case 92:    pushOOP(methodVariable(thisMethod, 28));    break;
  926.     case 93:    pushOOP(methodVariable(thisMethod, 29));    break;
  927.     case 94:    pushOOP(methodVariable(thisMethod, 30));    break;
  928.     case 95:    pushOOP(methodVariable(thisMethod, 31));    break;
  929.  
  930.     case  96:    storeReceiverVariable(self, 0, popOOP());    break;
  931.     case  97:    storeReceiverVariable(self, 1, popOOP());    break;
  932.     case  98:    storeReceiverVariable(self, 2, popOOP());    break;
  933.     case  99:    storeReceiverVariable(self, 3, popOOP());    break;
  934.     case 100:    storeReceiverVariable(self, 4, popOOP());    break;
  935.     case 101:    storeReceiverVariable(self, 5, popOOP());    break;
  936.     case 102:    storeReceiverVariable(self, 6, popOOP());    break;
  937.     case 103:    storeReceiverVariable(self, 7, popOOP());    break;
  938.  
  939.     case 104:    storeMethodTemporary(0, popOOP());    break;
  940.     case 105:    storeMethodTemporary(1, popOOP());    break;
  941.     case 106:    storeMethodTemporary(2, popOOP());    break;
  942.     case 107:    storeMethodTemporary(3, popOOP());    break;
  943.     case 108:    storeMethodTemporary(4, popOOP());    break;
  944.     case 109:    storeMethodTemporary(5, popOOP());    break;
  945.     case 110:    storeMethodTemporary(6, popOOP());    break;
  946.     case 111:    storeMethodTemporary(7, popOOP());    break;
  947.  
  948.     case 112: uncheckedPushOOP(self);        break;
  949.     case 113: uncheckedPushOOP(trueOOP);    break;
  950.     case 114: uncheckedPushOOP(falseOOP);     break;
  951.     case 115: uncheckedPushOOP(nilOOP);     break;
  952.     case 116: pushInt(-1);            break;
  953.     case 117: pushInt(0);            break;
  954.     case 118: pushInt(1);            break;
  955.     case 119: pushInt(2);            break;
  956.  
  957.     case 120: case 121: case 122: case 123:
  958.       switch (ival & 3) {
  959.       case 0: uncheckedPushOOP(self);       break;
  960.       case 1: uncheckedPushOOP(trueOOP);    break;
  961.       case 2: uncheckedPushOOP(falseOOP);     break;
  962.       case 3: uncheckedPushOOP(nilOOP);     break;
  963.       }
  964.  
  965.       /* fall through */
  966.  
  967.     case 124:            /* return stack top from method */
  968. abortMethod:            /* here if ^C is seen to abort things */
  969.       returnedValue = popOOP();
  970.  
  971.       if (isBlockContext(thisContextOOP)) {
  972.     /*
  973.      * We're executing in a block context and an explicit return is
  974.      * encountered.  This means that we are to return from the caller of
  975.      * the method that created the block context, no matter how many
  976.      * levels of message sending are between where we currently are and
  977.      * our parent method context.
  978.      */
  979.     blockContext = (BlockContext)oopToObj(thisContextOOP);
  980.     methodContextOOP = blockContext->home;
  981.     if (noParentContext(methodContextOOP)) {
  982.       /* ### this should send a message to Object of some kind */
  983.       errorf("Block returning to non-existent method context");
  984.       return;
  985.     }
  986.       } else {
  987.     methodContextOOP = thisContextOOP;
  988.     if (methodCount) {
  989.       methodCount--;
  990.       totalMethods++;
  991.     }
  992.       }
  993.  
  994.       exportRegs();
  995.       returnWithValue(returnedValue, methodContextOOP);
  996.       importRegs();        /* don't need to export these */
  997.       break;
  998.  
  999.     case 125:            /* return stack top from block to caller */
  1000.       returnedValue = popOOP();
  1001.       exportRegs();
  1002.       returnWithValue(returnedValue, thisContextOOP);
  1003.       importRegs();
  1004.       break;
  1005.  
  1006. /* 126, 127 unused by blue book, allocating 127 for debugger's
  1007.    breakpoint (not yet implemented) */
  1008.  
  1009.     case 128:
  1010.       ival2 = *ip++;
  1011.       switch (ival2 >> 6) {
  1012.       case 0:
  1013.     pushOOP(receiverVariable(self, ival2 & 63));
  1014.     break;
  1015.       case 1:
  1016.     pushOOP(methodTemporary(ival2 & 63));
  1017.     break;
  1018.       case 2:
  1019.     pushOOP(methodLiteral(thisMethod, ival2 & 63));
  1020.     break;
  1021.       case 3:
  1022.     pushOOP(methodVariable(thisMethod, ival2 & 63));
  1023.     break;
  1024.       }
  1025.       break;
  1026.  
  1027.     case 129:
  1028.       ival2 = *ip++;
  1029.       switch (ival2 >> 6) {
  1030.       case 0:
  1031.     storeReceiverVariable(self, ival2 & 63, stackTop());
  1032.     break;
  1033.       case 1:
  1034.     storeMethodTemporary(ival2 & 63, stackTop());
  1035.     break;
  1036.       case 2:
  1037.     errorf("Attempt to store into a method constant");
  1038.     break;
  1039.       case 3:
  1040.     storeMethodVariable(thisMethod, ival2 & 63, stackTop());
  1041.       }
  1042.       break;
  1043.  
  1044.     case 130:
  1045.       ival2 = *ip++;
  1046.       switch (ival2 >> 6) {
  1047.       case 0:
  1048.     storeReceiverVariable(self, ival2 & 63, popOOP());
  1049.     break;
  1050.       case 1:
  1051.     storeMethodTemporary(ival2 & 63, popOOP());
  1052.     break;
  1053.       case 2:
  1054.     errorf("Attempt to store into a method constant");
  1055.     break;
  1056.       case 3:
  1057.     storeMethodVariable(thisMethod, ival2 & 63, popOOP());
  1058.       }
  1059.       break;
  1060.  
  1061.     case 131:            /* send selector y (xxxyyyyy), x args */
  1062.       ival2 = *ip++;
  1063.       /* ### Send message knows the number of arguments that are being
  1064.      passed.  We could easily adjust the stack pointer here by doing
  1065.      some kind of popNOOPs.  The only trouble is what happens when
  1066.      the number of args doesn't agree with what the method is expecting,
  1067.      and we have to generate an error.  Also, if we don't export the sp
  1068.      here, we'll have to pass this as a parameter and sendMessage will
  1069.      have to export it anyway.  The cost of an export or import is
  1070.      about 1 or 2 instructions, so it may be cheap enough to just do
  1071.      in the places that we need to to it */
  1072.       exportRegs();        /* ### can this be removed? */
  1073.       sendMessage(methodLiteral(thisMethod, ival2 & 31), ival2 >> 5, false);
  1074.       importRegs();
  1075.       break;
  1076.  
  1077.     case 132:            /* send selector y (xxxxxxxx,yyyyyyyy) x args*/
  1078.       ival2 = *ip++;        /* the number of args */
  1079.       ival3 = *ip++;        /* the selector */
  1080.       exportRegs();
  1081.       sendMessage(methodLiteral(thisMethod, ival3), ival2, false);
  1082.       importRegs();
  1083.       break;
  1084.  
  1085.     case 133:            /* send super selector y (xxxyyyyy), x args*/
  1086.       ival2 = *ip++;
  1087.       exportRegs();
  1088.       sendMessage(methodLiteral(thisMethod, ival2 & 31), ival2 >> 5, true);
  1089.       importRegs();
  1090.       break;
  1091.  
  1092.     case 134:            /* send super y (xxxxxxxx,yyyyyyyy) x args */
  1093.       ival2 = *ip++;        /* the number of args */
  1094.       ival3 = *ip++;        /* the selector */
  1095.       exportRegs();
  1096.       sendMessage(methodLiteral(thisMethod, ival3), ival2, true);
  1097.       importRegs();
  1098.       break;
  1099.  
  1100.     case 135:
  1101.       popOOP();
  1102.       break;
  1103.  
  1104.     case 136:
  1105.       tempOOP = stackTop();
  1106.       pushOOP(tempOOP);
  1107.       break;
  1108.  
  1109.     case 137:             /* push active context */
  1110.       exportRegs();
  1111.       realizeMethodContexts();
  1112.       importRegs();
  1113.       pushOOP(thisContextOOP);
  1114.       break;
  1115.  
  1116.     case 144: case 145: case 146: case 147:
  1117.     case 148: case 149: case 150: case 151:
  1118.       ip += (ival & 7) + 1;    /* jump forward 1 to 8 bytes */
  1119.       break;
  1120.  
  1121.     case 152: case 153: case 154: case 155:
  1122.     case 156: case 157: case 158: case 159:
  1123.       if ((tempOOP = popOOP()) == falseOOP) { /* jump forward if false 1 to 8 bytes */
  1124.     ip += (ival & 7) + 1;
  1125.       } else if (tempOOP != trueOOP) {
  1126.     printf("Boolean instance required!\n");
  1127.     showBacktrace();
  1128.     stopExecuting(0);
  1129.       }
  1130.       break;
  1131.  
  1132.     case 160: case 161: case 162: case 163:
  1133.     case 164: case 165: case 166: case 167:
  1134.       ival2 = *ip++;        /* jump forward or back */
  1135.       ip += (((ival & 7) - 4) << 8) + ival2;
  1136.       break;
  1137.  
  1138.     case 168: case 169: case 170: case 171:
  1139.       ival2 = *ip++;
  1140.       if ((tempOOP = popOOP()) == trueOOP) {
  1141.     ip += ((ival & 3) << 8) + ival2;
  1142.       } else if (tempOOP != falseOOP) {
  1143.     printf("Boolean instance required!\n");
  1144.     showBacktrace();
  1145.     stopExecuting(0);
  1146.       }
  1147.       break;
  1148.  
  1149.     case 172: case 173: case 174: case 175:
  1150.       ival2 = *ip++;
  1151.       if ((tempOOP = popOOP()) == falseOOP) {
  1152.     ip += ((ival & 3) << 8) + ival2;
  1153.       } else if (tempOOP != trueOOP) {
  1154.     printf("Boolean instance required!\n");
  1155.     showBacktrace();
  1156.     stopExecuting(0);
  1157.       }
  1158.       break;
  1159.  
  1160. #define RAW_INT_OP(operator)        \
  1161. {                    \
  1162.   OOP    oop2;                \
  1163.   int    arg1, arg2;            \
  1164.   oop2 = popOOP();            \
  1165.   if (isInt(oop2)) {            \
  1166.     arg1 = toInt(tempOOP);        \
  1167.     arg2 = toInt(oop2);            \
  1168.     setStackTopInt(arg1 operator arg2);    \
  1169. /* why?    importRegs();*/            \
  1170.     break;                \
  1171.   }                    \
  1172.   unPop(1);                \
  1173. }
  1174.  
  1175. #define RAW_FLOAT_OP(operator)        \
  1176. {                    \
  1177.   OOP    oop2,oopResult;            \
  1178.   double farg1, farg2;            \
  1179.   oop2 = popOOP();            \
  1180.   if (isClass(oop2, floatClass)) {    \
  1181.     farg1 = floatOOPValue(tempOOP);    \
  1182.     farg2 = floatOOPValue(oop2);    \
  1183.     exportRegs();            \
  1184.     oopResult = floatNew(farg1 operator farg2); \
  1185.     importRegs();            \
  1186.     setStackTop(oopResult);        \
  1187. /* why?    importRegs();    */        \
  1188.     break;                \
  1189.   }                    \
  1190.   unPop(1);                \
  1191. }
  1192.  
  1193.  
  1194. #define INTERP_BASIC_OP(operator)    \
  1195.   tempOOP = stackAt(1);            \
  1196.   if (isInt(tempOOP)) {            \
  1197.     RAW_INT_OP(operator);        \
  1198.   } else if (oopClass(tempOOP) == floatClass) {    \
  1199.     RAW_FLOAT_OP(operator);        \
  1200.   }
  1201.  
  1202.  
  1203.  
  1204. #define RAW_BOOL_OP(operator)        \
  1205. {                    \
  1206.   OOP oop2;                \
  1207.   int arg1, arg2;            \
  1208.   oop2 = popOOP();            \
  1209.   if (isInt(oop2)) {            \
  1210.     arg1 = toInt(tempOOP);        \
  1211.     arg2 = toInt(oop2);            \
  1212.     setStackTopBoolean(arg1 operator arg2);    \
  1213. /* why?    importRegs(); */            \
  1214.     break;                \
  1215.   }                    \
  1216.   unPop(1);                \
  1217. }
  1218.  
  1219. #define RAW_BOOL_FLOAT_OP(operator)    \
  1220. {                    \
  1221.   OOP    oop2;                \
  1222.   double farg1, farg2;            \
  1223.   oop2 = popOOP();            \
  1224.   if (isClass(oop2, floatClass)) {    \
  1225.     farg1 = floatOOPValue(tempOOP);    \
  1226.     farg2 = floatOOPValue(oop2);    \
  1227.     setStackTopBoolean(farg1 operator farg2); \
  1228. /* why?    importRegs();*/            \
  1229.     break;                \
  1230.   }                    \
  1231.   unPop(1);                \
  1232. }
  1233.  
  1234. #define INTERP_BASIC_BOOL(operator)    \
  1235.   tempOOP = stackAt(1);            \
  1236.   if (isInt(tempOOP)) {            \
  1237.     RAW_BOOL_OP(operator);        \
  1238.   } else if (oopClass(tempOOP) == floatClass) {    \
  1239.     RAW_BOOL_FLOAT_OP(operator);    \
  1240.   }
  1241.  
  1242.     /* By "hard wiring" the definitions of these special operators, we get
  1243.      * the performance up to > 325K bytecodes/sec (SS1+,opt).  Yes, it means
  1244.      * that we cannot redefine + et al for Integer and Float, but I think
  1245.      * the trade is worth it.  Besides, with a little conspiring between the
  1246.      * compiler and the code here, it would be possible to have the code
  1247.      * test to see if the basic operator has been overridden and if so, do
  1248.      * a normal send.
  1249.      */
  1250.  
  1251.     case 176:
  1252.       INTERP_BASIC_OP(+);
  1253.       exportRegs();
  1254.       sendMessage(plusSymbol, 1, false);
  1255.       importRegs();
  1256.       break;
  1257.  
  1258.     case 177:
  1259.       INTERP_BASIC_OP(-);
  1260.       exportRegs();
  1261.       sendMessage(minusSymbol, 1, false);
  1262.       importRegs();
  1263.       break;
  1264.  
  1265.     case 178:
  1266.       INTERP_BASIC_BOOL(<);
  1267.       exportRegs();
  1268.       sendMessage(lessThanSymbol, 1, false);
  1269.       importRegs();
  1270.       break;
  1271.  
  1272.     case 179:
  1273.       INTERP_BASIC_BOOL(>);
  1274.       exportRegs();
  1275.       sendMessage(greaterThanSymbol, 1, false);
  1276.       importRegs();
  1277.       break;
  1278.  
  1279.     case 180:
  1280.       INTERP_BASIC_BOOL(<=);
  1281.       exportRegs();
  1282.       sendMessage(lessEqualSymbol, 1, false);
  1283.       importRegs();
  1284.       break;
  1285.  
  1286.     case 181:
  1287.       INTERP_BASIC_BOOL(>=);
  1288.       exportRegs();
  1289.       sendMessage(greaterEqualSymbol, 1, false);
  1290.       importRegs();
  1291.       break;
  1292.  
  1293.     case 182:
  1294.       INTERP_BASIC_BOOL(==);
  1295.       exportRegs();
  1296.       sendMessage(equalSymbol, 1, false);
  1297.       importRegs();
  1298.       break;
  1299.  
  1300.     case 183:
  1301.       INTERP_BASIC_BOOL(!=);
  1302.       exportRegs();
  1303.       sendMessage(notEqualSymbol, 1, false);
  1304.       importRegs();
  1305.       break;
  1306.  
  1307.     case 184:
  1308.       INTERP_BASIC_OP(*);
  1309.       exportRegs();
  1310.       sendMessage(timesSymbol, 1, false);
  1311.       importRegs();
  1312.       break;
  1313.  
  1314.     case 185:
  1315.       exportRegs();
  1316.       sendMessage(divideSymbol, 1, false);
  1317.       importRegs();
  1318.       break;
  1319.  
  1320.     case 186:
  1321.       exportRegs();
  1322.       sendMessage(remainderSymbol, 1, false);
  1323.       importRegs();
  1324.       break;
  1325.  
  1326.     case 187:
  1327.       exportRegs();
  1328.       /* The compiler won't even generate this bytecode */
  1329.       sendMessage(plusSymbol, 1, false); /* @, not implemented */
  1330.       importRegs();
  1331.       break;
  1332.  
  1333.     case 188:
  1334.       tempOOP = stackAt(1);
  1335.       if (isInt(tempOOP)) {
  1336.     OOP    oop2;
  1337.     int    arg1, arg2;
  1338.     oop2 = popOOP();
  1339.     if (isInt(oop2)) {
  1340.       arg1 = toInt(tempOOP);
  1341.       arg2 = toInt(oop2);
  1342.       if (arg2 >= 0) {
  1343.         setStackTopInt(arg1 << arg2);
  1344.       } else {
  1345.         setStackTopInt(arg1 >> -arg2);
  1346.       }
  1347.       break;
  1348.     }
  1349.     unPop(1);
  1350.       }
  1351.       exportRegs();
  1352.       sendMessage(bitShiftColonSymbol, 1, false);
  1353.       importRegs();
  1354.       break;
  1355.  
  1356.     case 189:
  1357.       tempOOP = stackAt(1);
  1358.       if (isInt(tempOOP)) {
  1359.     RAW_INT_OP(/);
  1360.       }
  1361.       exportRegs();
  1362.       sendMessage(integerDivideSymbol, 1, false);
  1363.       importRegs();
  1364.       break;
  1365.  
  1366.     case 190:
  1367.       tempOOP = stackAt(1);
  1368.       if (isInt(tempOOP)) {
  1369.     RAW_INT_OP(&);
  1370.       }
  1371.       exportRegs();
  1372.       sendMessage(bitAndColonSymbol, 1, false);
  1373.       importRegs();
  1374.       break;
  1375.  
  1376.     case 191:
  1377.       tempOOP = stackAt(1);
  1378.       if (isInt(tempOOP)) {
  1379.     RAW_INT_OP(|);
  1380.       }
  1381.       exportRegs();
  1382.       sendMessage(bitOrColonSymbol, 1, false);
  1383.       importRegs();
  1384.       break;
  1385.  
  1386. #ifdef bogus /* Sat Jan  5 22:12:45 1991 */
  1387. /**/    case 176: case 177: case 178: case 179:
  1388. /**/    case 180: case 181: case 182: case 183:
  1389. /**/    case 184: case 185: case 186: case 187:
  1390. /**/    case 188: case 189: case 190: case 191:
  1391. /**/                /* send math message */
  1392. /**/      exportRegs();
  1393. /**/      sendMessage(*mathSelectors[ival & 15], 1, false);
  1394. /**/      importRegs();
  1395. /**/      break;
  1396. #endif /* bogus Sat Jan  5 22:12:45 1991 */
  1397.  
  1398.     case 192:
  1399.       exportRegs();
  1400.       sendMessage(atColonSymbol, 1, false);
  1401.       importRegs();
  1402.       break;
  1403.  
  1404.     case 193:
  1405.       exportRegs();
  1406.       sendMessage(atColonPutColonSymbol, 2, false);
  1407.       importRegs();
  1408.       break;
  1409.  
  1410.     case 194:
  1411.       exportRegs();
  1412.       sendMessage(sizeSymbol, 0, false);
  1413.       importRegs();
  1414.       break;
  1415.  
  1416.     case 195:
  1417.       exportRegs();
  1418.       sendMessage(nextSymbol, 0, false);
  1419.       importRegs();
  1420.       break;
  1421.  
  1422.     case 196:
  1423.       exportRegs();
  1424.       sendMessage(nextPutColonSymbol, 1, false);
  1425.       importRegs();
  1426.       break;
  1427.  
  1428.     case 197:
  1429.       exportRegs();
  1430.       sendMessage(atEndSymbol, 0, false);
  1431.       importRegs();
  1432.       break;
  1433.  
  1434.     case 198:
  1435.       exportRegs();
  1436.       sendMessage(sameObjectSymbol, 1, false);
  1437.       importRegs();
  1438.       break;
  1439.  
  1440.     case 199:
  1441.       exportRegs();
  1442.       sendMessage(classSymbol, 0, false);
  1443.       importRegs();
  1444.       break;
  1445.  
  1446.     case 200:
  1447.       exportRegs();
  1448.       sendMessage(blockCopyColonSymbol, 1, false);
  1449.       importRegs();
  1450.       break;
  1451.  
  1452.     case 201:
  1453.       exportRegs();
  1454.       sendMessage(valueSymbol, 0, false);
  1455.       importRegs();
  1456.       break;
  1457.  
  1458.     case 202:
  1459.       exportRegs();
  1460.       sendMessage(valueColonSymbol, 1, false);
  1461.       importRegs();
  1462.       break;
  1463.  
  1464.     case 203:
  1465.       exportRegs();
  1466.       sendMessage(doColonSymbol, 1, false);
  1467.       importRegs();
  1468.       break;
  1469.  
  1470.     case 204:
  1471.       exportRegs();
  1472.       sendMessage(newSymbol, 0, false);
  1473.       importRegs();
  1474.       break;
  1475.  
  1476.     case 205:
  1477.       exportRegs();
  1478.       sendMessage(newColonSymbol, 1, false);
  1479.       importRegs();
  1480.       break;
  1481.  
  1482.     case 206:
  1483.       exportRegs();
  1484.       sendMessage(nilSymbol, 0, /* unimplemented selector */
  1485.           false);
  1486.       importRegs();
  1487.       break;
  1488.  
  1489.     case 207:
  1490.       exportRegs();
  1491.       sendMessage(nilSymbol, 0, /* unimplemented selector */
  1492.           false);
  1493.       importRegs();
  1494.       break;
  1495.  
  1496. #ifdef old_code /* Mon Jan  7 21:58:21 1991 */
  1497. /**/    case 192: case 193: case 194: case 195:
  1498. /**/    case 196: case 197: case 198: case 199:
  1499. /**/    case 200: case 201: case 202: case 203:
  1500. /**/    case 204: case 205: case 206: case 207:
  1501. /**/                /* send special message */
  1502. /**/      exportRegs();
  1503. /**/      sendMessage(*specialMessages[ival & 15].selector,
  1504. /**/          specialMessages[ival & 15].args, false);
  1505. /**/      importRegs();
  1506. /**/      break;
  1507. #endif /* old_code Mon Jan  7 21:58:21 1991 */
  1508.  
  1509.     case 208: case 209: case 210: case 211:
  1510.     case 212: case 213: case 214: case 215:
  1511.     case 216: case 217: case 218: case 219:
  1512.     case 220: case 221: case 222: case 223:
  1513.                 /* send selector no args */
  1514.       exportRegs();
  1515.       sendMessage(methodLiteral(thisMethod, ival & 15), 0, false);
  1516.       importRegs();
  1517.       break;
  1518.  
  1519.     case 224: case 225: case 226: case 227:
  1520.     case 228: case 229: case 230: case 231:
  1521.     case 232: case 233: case 234: case 235:
  1522.     case 236: case 237: case 238: case 239:
  1523.                 /* send selector 1 arg */
  1524.       exportRegs();
  1525.       sendMessage(methodLiteral(thisMethod, ival & 15), 1, false);
  1526.       importRegs();
  1527.       break;
  1528.  
  1529.     case 240: case 241: case 242: case 243:
  1530.     case 244: case 245: case 246: case 247:
  1531.     case 248: case 249: case 250: case 251:
  1532.     case 252: case 253: case 254: case 255:
  1533.                 /* send selector 2 args */
  1534.       exportRegs();
  1535.       sendMessage(methodLiteral(thisMethod, ival & 15), 2, false);
  1536.       importRegs();
  1537.       break;
  1538.  
  1539.     default:
  1540.       errorf("Illegal byte code %d executed\n", ival);
  1541.       break;
  1542.     }
  1543.   }
  1544.   inInterpreter = false;
  1545.  
  1546.   exportRegs();
  1547. }
  1548.  
  1549. static void changeProcessContext(newProcess)
  1550. OOP    newProcess;
  1551. {
  1552.   MethodContext thisContext, methodContext;
  1553.   OOP        processOOP, methodContextOOP;
  1554.   Process    process;
  1555.   ProcessorScheduler processor;
  1556.   
  1557.   realizeMethodContexts();    /* clean things up */
  1558.  
  1559.   switchToProcess = nilOOP;
  1560.   if (!isNil(thisContextOOP)) {
  1561.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  1562.     /* save old context information */
  1563.     thisContext->ipOffset = fromInt(relativeByteIndex(ip, thisMethod));
  1564.     /* leave sp pointing to receiver, which is replaced on return with value*/
  1565.     thisContext->spOffset = fromInt(sp - thisContext->contextStack);
  1566.   }
  1567.  
  1568.   processOOP = getActiveProcess();
  1569.   process = (Process)oopToObj(processOOP);
  1570.   prepareToStore(processOOP, thisContextOOP);
  1571.   process->suspendedContext = thisContextOOP;
  1572.  
  1573.   processor = (ProcessorScheduler)oopToObj(processorOOP);
  1574.   prepareToStore(processorOOP, newProcess);
  1575.   processor->activeProcess = newProcess;
  1576.   
  1577.   process = (Process)oopToObj(newProcess);
  1578.  
  1579.   thisContextOOP = process->suspendedContext;
  1580.   /* ### should this be block context? */
  1581.   thisContext = (MethodContext)oopToObj(thisContextOOP);
  1582.  
  1583.   methodContextOOP = getMethodContext(thisContextOOP);
  1584.  
  1585.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  1586.   thisMethod = methodContext->method;
  1587.   ip = toInt(thisContext->ipOffset) + getMethodByteCodes(thisMethod);
  1588.   sp = thisContext->contextStack + toInt(thisContext->spOffset);
  1589.  
  1590.   /* temporaries and self live in the method, not in the block */
  1591.   temporaries = methodContext->contextStack;
  1592.   self = methodContext->receiver;
  1593. }
  1594.  
  1595.  
  1596. /*
  1597.  *    static Boolean noParentContext(methodContextOOP)
  1598.  *
  1599.  * Description
  1600.  *
  1601.  *    Returns true if there is no parent context for "methodContextOOP".
  1602.  *    This occurs when the method context has been returned from, but it had
  1603.  *    created a block context during its execution and so it was not
  1604.  *    deallocated when it returned.  Now some block context is trying to
  1605.  *    return from that method context, but where to return to is undefined.
  1606.  *
  1607.  * Inputs
  1608.  *
  1609.  *    methodContextOOP: 
  1610.  *        An OOP that is the method context to be examined.
  1611.  *
  1612.  * Outputs
  1613.  *
  1614.  *    True if the current method has no parent, false otherwise.
  1615.  */
  1616. static Boolean noParentContext(methodContextOOP)
  1617. OOP methodContextOOP;
  1618. {
  1619.   MethodContext methodContext;
  1620.  
  1621.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  1622.  
  1623.   return (isNil(methodContext->sender));
  1624. }
  1625.  
  1626. #ifdef ACCESSOR_DEBUGGING
  1627. /*
  1628.  *    static OOP getMethodContext(contextOOP)
  1629.  *
  1630.  * Description
  1631.  *
  1632.  *    Returns the method context for either a block context or a method
  1633.  *    context. 
  1634.  *
  1635.  * Inputs
  1636.  *
  1637.  *    contextOOP: Block or Method context OOP
  1638.  *        
  1639.  *
  1640.  * Outputs
  1641.  *
  1642.  *    Method context for CONTEXTOOP.
  1643.  */
  1644. static OOP getMethodContext(contextOOP)
  1645. OOP    contextOOP;
  1646. {
  1647.   return (getMethodContextInternal(contextOOP));
  1648. }
  1649. #endif /* ACCESSOR_DEBUGGING */
  1650.  
  1651. long numMethods, numBlocks;
  1652. long totalRealized = 0;
  1653. OOP        fakeList = nil;
  1654.  
  1655.  
  1656. static OOP allocMethodContext()
  1657. {
  1658.   FakeOOP    f;
  1659.   OOP        fakeOOP;
  1660.   MethodContext    methodContext;
  1661.  
  1662.   if (fakeList) {
  1663.     fakeOOP = fakeList;
  1664.     methodContext = (MethodContext)oopToObj(fakeList);
  1665.     fakeList = methodContext->sender;
  1666. /* dprintf("[[[[ Allocing fake %8x\n", fakeOOP); */
  1667.     return (fakeOOP);
  1668.   }
  1669.  
  1670.   f = (FakeOOP)malloc(sizeof(struct FakeContextOOP));
  1671.   f->mc.objSize = sizeof(struct MethodContextStruct) >> 2;
  1672.   f->mc.objClass = methodContextClass;
  1673.   nilFill(&f->mc.sender, 8/* num oops w/o stack */);
  1674.   
  1675.   f->oop.object = (Object)f;    /* &f->mc optimized */
  1676.   f->oop.flags = F_FAKE;
  1677.  
  1678. /* dprintf("[[[[ Allocing new fakes %8x\n", &f->oop); */
  1679.   return (&f->oop);
  1680. }
  1681.  
  1682.  
  1683. #ifdef old_code /* Sat Dec 29 14:53:04 1990 */
  1684. /**/static OOP allocMethodContext()
  1685. /**/{
  1686. /**/  MethodContext methodContext;
  1687. /**/
  1688. /**/  methodContext = (MethodContext)instantiateWith(methodContextClass,
  1689. /**/                         CONTEXT_STACK_SIZE);
  1690. /**/methodCount++;
  1691. /**/numMethods++;
  1692. /**/  return (allocOOP(methodContext));
  1693. /**/}
  1694. #endif /* old_code Sat Dec 29 14:53:04 1990 */
  1695.  
  1696. static OOP allocBlockContext()
  1697. {
  1698.   BlockContext blockContext;
  1699.  
  1700.   blockContext = (BlockContext)instantiateWith(blockContextClass,
  1701.                            CONTEXT_STACK_SIZE);
  1702. #ifndef OPTIMIZE
  1703. totalRealized += methodCount;
  1704. methodCount = 0;
  1705. numBlocks++;
  1706. #endif
  1707.  
  1708.   return (allocOOP(blockContext));
  1709. }
  1710.  
  1711.  
  1712. static void deallocMethodContext(methodContextOOP)
  1713. OOP    methodContextOOP;
  1714. {
  1715.   MethodContext    methodContext;
  1716.  
  1717. #ifndef OPTIMIZE
  1718.   if (!isFake(methodContextOOP)) {
  1719.     printf("!!! Deallocating real method context\n");
  1720.     return;
  1721.   }
  1722. #endif
  1723.  
  1724.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  1725.  
  1726.   methodContext->sender = fakeList;
  1727.   fakeList = methodContextOOP;
  1728. }
  1729.  
  1730.  
  1731. void realizeMethodContexts()
  1732. {
  1733.   MethodContext methodContext;
  1734.   int        spOffset;
  1735.  
  1736.   if (!isFake(thisContextOOP)) {
  1737.     /* Should never have a non-fake on top of a fake, so we can short circuit
  1738.      * this way.  Also takes care of when thisContextOOP is a block */
  1739.     return;
  1740.   }
  1741.  
  1742.   methodContext = (MethodContext)oopToObj(thisContextOOP);
  1743.  
  1744.   spOffset = sp - methodContext->contextStack;
  1745.   methodContext->spOffset = fromInt(spOffset);
  1746.  
  1747.   thisContextOOP = realizeContext(thisContextOOP);
  1748.   methodContext = (MethodContext)oopToObj(thisContextOOP);
  1749.  
  1750.   sp = methodContext->contextStack + spOffset;
  1751.   temporaries = methodContext->contextStack;
  1752.   /* self doesn't change after realization (???gc may change it?) */
  1753. }
  1754.  
  1755. /* !!! debug */
  1756.  
  1757. OOP junkContext;
  1758.  
  1759. #ifdef bogus /* Sun Nov 24 19:29:31 1991 */
  1760. /**/printContext()
  1761. /**/{
  1762. /**//*   dprintf("thisContextOOP = %8x\n", thisContextOOP); */
  1763. /**/  junkContext = thisContextOOP;
  1764. /**/}
  1765. #endif /* bogus Sun Nov 24 19:29:31 1991 */
  1766.  
  1767.  
  1768. static OOP realizeContext(methodContextOOP) 
  1769. OOP    methodContextOOP;
  1770. {
  1771.   MethodContext methodContext, newContext;
  1772.   int        spOffset;
  1773.   OOP        sender;
  1774.  
  1775. /*  if (!isFake(methodContextOOP)) {
  1776.     return (methodContextOOP);
  1777.   }
  1778. */
  1779.  
  1780.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  1781.   if (isFake(methodContext->sender)) {
  1782.     sender = realizeContext(methodContext->sender);
  1783.     /*
  1784.      * doing the realizeContext may have moved method context to the other
  1785.      * space, so we can't count on our cached version
  1786.      */
  1787.     if (methodContext != (MethodContext)oopToObj(methodContextOOP)) {
  1788.       printf("in realize got a bug!!!\n");
  1789.     }
  1790.     methodContext = (MethodContext)oopToObj(methodContextOOP);
  1791.     methodContext->sender = sender;
  1792.   }
  1793.  
  1794.   newContext = (MethodContext)newInstanceWith(methodContextClass,
  1795.                           CONTEXT_STACK_SIZE);
  1796. #ifdef debug_checking /* Tue Dec 31 15:14:55 1991 */
  1797. /**/    if (methodContext != (MethodContext)oopToObj(methodContextOOP)) {
  1798. /**/      printf("in realize got a bug also!!!\n");
  1799. /**/    }
  1800. #endif /* debug_checking Tue Dec 31 15:14:55 1991 */
  1801.  
  1802.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  1803.   spOffset = toInt(methodContext->spOffset);
  1804.  
  1805.   memcpy(newContext, methodContext, sizeof(struct MethodContextStruct)
  1806.      - ((CONTEXT_STACK_SIZE - spOffset - 1) * sizeof(OOP)) );
  1807.   nilFill(newContext->contextStack + spOffset + 1,
  1808.       CONTEXT_STACK_SIZE - spOffset - 1);
  1809.  
  1810.   /* slower, but allows centralized debugging/modification for the time
  1811.    * being */
  1812.   deallocMethodContext(methodContextOOP);
  1813.   /*methodContext->sender = (OOP)fakeList;
  1814.   fakeList = methodContextOOP; */
  1815.  
  1816.   return (allocOOP(newContext));
  1817. }
  1818.  
  1819.  
  1820.  
  1821. #ifdef ACCESSOR_DEBUGGING
  1822. /*
  1823.  *    static Boolean isBlockContext(contextOOP)
  1824.  *
  1825.  * Description
  1826.  *
  1827.  *    Returns true if "contextOOP" is a block context.
  1828.  *
  1829.  * Inputs
  1830.  *
  1831.  *    contextOOP: 
  1832.  *        an OOP for a context that is to be checked.
  1833.  *
  1834.  * Outputs
  1835.  *
  1836.  *    True if it's a block context, false otherwise.
  1837.  */
  1838. static Boolean isBlockContext(contextOOP)
  1839. OOP    contextOOP;
  1840. {
  1841.   return (oopClass(contextOOP) == blockContextClass);
  1842. }
  1843. #endif /* ACCESSOR_DEBUGGING */
  1844.  
  1845.  
  1846. /*
  1847.  * on entry to this routine, the stack should have the receiver and the
  1848.  * arguments pushed on the stack.  We need to get a new context,
  1849.  * setup things like the IP, SP, and Temporary pointers, and then
  1850.  * return.   Note that this routine DOES NOT invoke the interpreter; it merely
  1851.  * sets up a new context so that calling (or, more typically, returning to) the
  1852.  * interpreter will operate properly.  This kind of sending is for normal
  1853.  * messages only.  Things like sending a "value" message to a block context are
  1854.  * handled by primitives which do similar things, but they use information from
  1855.  * the block and method contexts that we don't have available (or need) here.
  1856.  */
  1857.  
  1858. void sendMessage(sendSelector, sendArgs, sendToSuper)
  1859. OOP    sendSelector;
  1860. int    sendArgs;
  1861. Boolean    sendToSuper;
  1862. {
  1863.   OOP        methodOOP, receiver, methodClass, receiverClass,
  1864.         argsArray, newContextOOP;
  1865.   MethodContext thisContext, newContext;
  1866.   MethodHeader    header;
  1867.   int        i, numTemps;
  1868.   long        hashIndex;
  1869.  
  1870.   if (!sendToSuper) {
  1871.     receiver = getStackReceiver(sendArgs);
  1872.     if (isInt(receiver)) {
  1873.       receiverClass = integerClass;
  1874.     } else {
  1875.       receiverClass = oopClass(receiver);
  1876.     }
  1877.   } else {
  1878.     methodClass = getMethodClass(thisMethod);
  1879.     receiverClass = superClass(methodClass);
  1880.     receiver = self;
  1881.   }
  1882.  
  1883.   /* hash the selector and the class of the receiver together using XOR.
  1884.    * Since both are pointers to long word aligned quantities, shift over
  1885.    * by 2 bits to remove the useless low order zeros.  Also, since
  1886.    * they are addresses in the oopTable, and since oopTable entries are
  1887.    * 8 bytes long, we can profitably shift over 3 bits */
  1888. /*  hashIndex = ((long)sendSelector ^ (long)receiverClass) >> 4; */
  1889.   hashIndex = ((long)sendSelector ^ (long)receiverClass) >> 3;
  1890.   hashIndex &= (METHOD_CACHE_SIZE - 1);
  1891.  
  1892.  
  1893.   if (methodCacheSelectors[hashIndex] == sendSelector
  1894.       && methodCacheClasses[hashIndex] == receiverClass) {
  1895.     /* :-) CACHE HIT!!! (-: */
  1896.     methodOOP = methodCacheMethods[hashIndex];
  1897.     methodClass = methodCacheMethodClasses[hashIndex];
  1898.     cacheHits++;
  1899.   } else {
  1900.     /* :-( cache miss )-: */
  1901.     methodOOP = findMethod(receiverClass, sendSelector, &methodClass);
  1902.     if (isNil(methodOOP)) {
  1903.       argsArray = arrayNew(sendArgs);
  1904.       for (i = 0; i < sendArgs; i++) {
  1905.     arrayAtPut(argsArray, i+1, stackAt(sendArgs-i-1));
  1906.       }
  1907.       popNOOPs(sendArgs);
  1908.       pushOOP(messageNewArgs(sendSelector, argsArray));
  1909.       sendMessage(doesNotUnderstandColonSymbol, 1, false);
  1910.       return;
  1911.     }
  1912.     methodCacheSelectors[hashIndex] = sendSelector;
  1913.     methodCacheClasses[hashIndex] = receiverClass;
  1914.     methodCacheMethods[hashIndex] = methodOOP;
  1915.     methodCacheMethodClasses[hashIndex] = methodClass;
  1916.     collide[hashIndex]++;
  1917.     cacheMisses++;
  1918.   }
  1919.  
  1920.   header = getMethodHeader(methodOOP);
  1921.   if (header.numArgs != sendArgs) {
  1922.     errorf("invalid number of arguments %d, expecting %d", sendArgs,
  1923.        header.numArgs);
  1924.     return;
  1925.   }
  1926.  
  1927.   if (header.headerFlag != 0) {
  1928.     switch (header.headerFlag) {
  1929.     case 1:            /* return self */
  1930.       if (sendArgs != 0) {
  1931.     errorf("method returns primitive self, but has args!!!");
  1932.     return;
  1933.       }
  1934.  
  1935.       /* self is already on the stack...so we leave it */
  1936.       return;
  1937.  
  1938.     case 2:            /* return instance variable */
  1939.       if (sendArgs != 0) {
  1940.     errorf("method returns primitive instance variable, but has args!!!");
  1941.     return;
  1942.       }
  1943.       /* replace receiver with the returned instance variable */
  1944.       setStackTop(receiverVariable(receiver, header.numTemps));
  1945.       return;
  1946.  
  1947.     case 3:            /* send primitive */
  1948.       if (!executePrimitiveOperation(header.primitiveIndex, sendArgs,
  1949.                      methodOOP)) {
  1950.     return;
  1951.       }
  1952.       /* primitive failed.  Invoke the normal method */
  1953.       break;
  1954.     }
  1955.   }
  1956.  
  1957.   if (!isNil(thisContextOOP)) {
  1958.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  1959.     /* save old context information */
  1960.     thisContext->ipOffset = fromInt(relativeByteIndex(ip, thisMethod));
  1961.     /* leave sp pointing to receiver, which is replaced on return with value*/
  1962.     thisContext->spOffset = fromInt(sp - sendArgs - thisContext->contextStack);
  1963.   }
  1964.  
  1965.   /* prepare the new state */
  1966.   newContextOOP = allocMethodContext();
  1967.   newContext = (MethodContext)oopToObj(newContextOOP);
  1968. /* dprintf("{{{{ sender for %8x is %8x (send)\n", newContext, thisContextOOP); */
  1969.   newContext->sender = thisContextOOP;
  1970.   maybeMoveOOP(methodOOP);
  1971.   newContext->method = methodOOP;
  1972.   maybeMoveOOP(methodClass);
  1973.   newContext->methodClass = methodClass;
  1974.   newContext->hasBlock = nilOOP;    /* becomes non-nil when a block is created */
  1975.  
  1976.   /* copy self and sendArgs arguments into new context */
  1977.   maybeMoveOOP(sendSelector);
  1978.   newContext->selector = sendSelector;
  1979.   maybeMoveOOP(receiver);
  1980.   newContext->receiver = receiver;
  1981.   memcpy(newContext->contextStack, &sp[-sendArgs+1], (sendArgs) * sizeof(OOP));
  1982.   for (i = 0; i < sendArgs; i++) {
  1983.     maybeMoveOOP(newContext->contextStack[i]);
  1984.   }
  1985.  
  1986.   numTemps = header.numTemps;
  1987.   nilFill(&newContext->contextStack[sendArgs], numTemps);
  1988.  
  1989.   sp = &newContext->contextStack[sendArgs + numTemps - 1];
  1990.                 /* 1 before the actual start of stack */
  1991.  
  1992.   thisMethod = methodOOP;
  1993.   thisContextOOP = newContextOOP;
  1994.   
  1995.   temporaries = newContext->contextStack;
  1996.   self = newContext->receiver;
  1997.   ip = getMethodByteCodes(thisMethod);
  1998.   /* ### fix getmethodbytecodes to check for actual byte codes in method */
  1999. }
  2000.  
  2001.  
  2002. /*
  2003.  *    static void returnWithValue(returnedValue, returnContext)
  2004.  *
  2005.  * Description
  2006.  *
  2007.  *    Return from context "returnContext" with value "returnedValue".  Note
  2008.  *    that this context may not be the current context.  If returnContext
  2009.  *    is not a block context, then we need to carefully unwind the
  2010.  *    "method call stack".  Here carefully means that we examine each
  2011.  *    context.  If it's a block context then we cannot deallocate it.  If
  2012.  *    it's a method context, and if during its execution it did not create a
  2013.  *    block context, then we can deallocate it.  Otherwise, we need to mark
  2014.  *    it as returned (set the sender to nilOOP) and continue up the call
  2015.  *    chain until we reach returnContext.
  2016.  *
  2017.  * Inputs
  2018.  *
  2019.  *    returnedValue: 
  2020.  *        Value to be put on the stack in the sender's context.
  2021.  *    returnContext: 
  2022.  *        The context to return from, an OOP.  This may not be the
  2023.  *        current context.
  2024.  *
  2025.  */
  2026. static void returnWithValue(returnedValue, returnContext)
  2027. OOP    returnedValue, returnContext;
  2028. {
  2029.   MethodContext    thisContext, methodContext;
  2030.   OOP        oldContextOOP, methodContextOOP;
  2031.  
  2032.   while (thisContextOOP != returnContext) {
  2033.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  2034.     if (isBlockContext(thisContextOOP)) {
  2035.       thisContextOOP = ((BlockContext)thisContext)->caller;
  2036.     } else {
  2037.       oldContextOOP = thisContextOOP;
  2038.       thisContextOOP = thisContext->sender; /* ### what if sender is nil? */
  2039.       if (isFake(oldContextOOP)) {
  2040.     deallocMethodContext(oldContextOOP);
  2041.       } else if (!isNil(thisContext->hasBlock)) {
  2042.     /* This context created a block.  Since we don't know who is holding
  2043.        the block, we must presume that it is global.  Since any blocks
  2044.        created by this method can reference arguments and temporaries
  2045.        of this method, we must keep the method context around, but mark
  2046.        it as non-returnable so that attempts to return from it to an
  2047.        undefined place will lose. */
  2048. /* dprintf("{{{{ sender for %8x is nilOOP (returnWValue)\n", thisContext); */
  2049.     thisContext->sender = nilOOP;
  2050.       }
  2051.     }
  2052.   }
  2053.  
  2054.   /* when we're here, we've deallocated any intervening contexts, and now
  2055.      we need to restore the state of the world as it was before we were called.
  2056.      Our caller has set the stack pointer to where we should place the
  2057.      return value, so all we need do is restore the interpreter's state and
  2058.      we're set. */
  2059.   /* ??? Geez, this feels clumsy.  We could have merged the "pop context"
  2060.      code below with the while loop above, using a do...while, but I wonder
  2061.      if, over the long haul, the code for popping the final context will
  2062.      be a special case and so will need separate code.  */
  2063.   oldContextOOP = thisContextOOP;
  2064.   thisContext = (MethodContext)oopToObj(thisContextOOP);
  2065.   thisContextOOP = thisContext->sender;
  2066.  
  2067.   if (isFake(oldContextOOP)) {
  2068.     deallocMethodContext(oldContextOOP);
  2069.   } else if (!isBlockContext(oldContextOOP)) {
  2070.     if (!isNil(thisContext->hasBlock)) {
  2071.       /* mark it so block can't return from method */
  2072. /* dprintf("{{{{ sender for %8x is nilOOP (returnWValue)\n", thisContext); */
  2073.       thisContext->sender = nilOOP;
  2074.     }
  2075.   }
  2076.  
  2077.   /* ### this can be removed when all the maybeMoveOOPs go -- all it does is
  2078.    * slow things down
  2079.    */
  2080.   if (!isFake(thisContextOOP)) {
  2081.     maybeMoveOOP(thisContextOOP);
  2082.   }
  2083.   
  2084.   thisContext = (MethodContext)oopToObj(thisContextOOP);
  2085.  
  2086.   methodContextOOP = getMethodContext(thisContextOOP);
  2087.   if (methodContextOOP != thisContextOOP) { /* if we're a block */
  2088.     maybeMoveOOP(methodContextOOP); /* validate containing method */
  2089.   }
  2090.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  2091.   thisMethod = methodContext->method;
  2092.   maybeMoveOOP(thisMethod);
  2093.   ip = toInt(thisContext->ipOffset) + getMethodByteCodes(thisMethod);
  2094.   sp = thisContext->contextStack + toInt(thisContext->spOffset);
  2095.  
  2096.   /* temporaries and self live in the method, not in the block */
  2097.   temporaries = methodContext->contextStack;
  2098.   self = methodContext->receiver;
  2099.   maybeMoveOOP(self);
  2100.  
  2101.   maybeMoveOOP(returnedValue);
  2102.  
  2103.   setStackTop(returnedValue);
  2104. }
  2105.  
  2106.  
  2107.  
  2108. /***********************************************************************
  2109.  *
  2110.  *    Simple Method Object Accessors
  2111.  *
  2112.  ***********************************************************************/
  2113.  
  2114. #ifdef ACCESSOR_DEBUGGING
  2115.  
  2116. static OOP receiverVariable(receiver, index)
  2117. OOP    receiver;
  2118. int    index;
  2119. {
  2120.   if (!inBounds(receiver, index)) {
  2121.     errorf("Index out of bounds %d", index);
  2122.   }
  2123.   return (oopToObj(receiver)->data[index]);
  2124. }
  2125.  
  2126. static OOP getStackReceiver(numArgs)
  2127. int    numArgs;
  2128. {
  2129.   /* this is correct: numArgs == 0 means that there's just the receiver
  2130.      on the stack, at 0.  numArgs = 1 means that at location 0 is the arg,
  2131.      location 1 is the receiver. */
  2132.   return (stackAt(numArgs));
  2133. }
  2134.  
  2135. static OOP methodTemporary(index)
  2136. int    index;
  2137. {
  2138.   return (temporaries[index]);
  2139. }
  2140.  
  2141. static OOP methodLiteral(methodOOP, index)
  2142. OOP    methodOOP;
  2143. int    index;
  2144. {
  2145.   Method    method = (Method)oopToObj(methodOOP);
  2146.  
  2147.   /* ### check for in bounds with index */
  2148.   return (method->literals[index]);
  2149. }
  2150.  
  2151. static OOP methodVariable(methodOOP, index)
  2152. OOP    methodOOP;
  2153. int    index;
  2154. {
  2155.   Method    method = (Method)oopToObj(methodOOP);
  2156.  
  2157.   return (associationValue(method->literals[index]));
  2158. }
  2159.  
  2160. static Byte *getMethodByteCodes(methodOOP)
  2161. OOP    methodOOP;
  2162. {
  2163.   Method    method;
  2164.  
  2165.   if (isNil(methodOOP)) {
  2166.     return (nil);
  2167.   }
  2168.  
  2169.   method = (Method)oopToObj(methodOOP);
  2170.  
  2171.   /* skip the header and the number of literals to find the start of the
  2172.      byte codes */
  2173.   return ((Byte *)&method->literals[method->header.numLiterals]);
  2174. }
  2175.  
  2176. static MethodHeader getMethodHeader(methodOOP)
  2177. OOP    methodOOP;
  2178. {
  2179.   Method    method;
  2180.  
  2181.   method = (Method)oopToObj(methodOOP);
  2182.   return (method->header);
  2183. }
  2184.  
  2185. /*
  2186.  *    static OOP getMethodClass(method)
  2187.  *
  2188.  * Description
  2189.  *
  2190.  *    This is called when a method contains a send to "super".  The compiler
  2191.  *    is supposed to notice a send to "super", and make sure that the last
  2192.  *    literal of a method is an association between the symbol for the
  2193.  *    class of the method and the class of the method itself.  This routine
  2194.  *    returns the class of the method itself using this association.
  2195.  *
  2196.  * Inputs
  2197.  *
  2198.  *    method: An OOP that represents a method.
  2199.  *
  2200.  * Outputs
  2201.  *
  2202.  *    An OOP for the class of the method.
  2203.  */
  2204. static OOP getMethodClass(methodOOP)
  2205. OOP    methodOOP;
  2206. {
  2207.   Method    method;
  2208.   OOP        associationOOP;
  2209.  
  2210.   method = (Method)oopToObj(methodOOP);
  2211.   associationOOP = method->literals[method->header.numLiterals - 1];
  2212.   return (associationValue(associationOOP));
  2213. }
  2214.  
  2215. /***********************************************************************
  2216.  *
  2217.  *    Simple Method Object Storing routines.
  2218.  *
  2219.  ***********************************************************************/
  2220.  
  2221.  
  2222. static void storeReceiverVariable(receiver, index, oop)
  2223. OOP    receiver, oop;
  2224. int    index;
  2225. {
  2226.   if (!inBounds(receiver, index)) {
  2227.     errorf("Index out of bounds %d", index);
  2228.   }
  2229.   prepareToStore(receiver, oop);
  2230.   oopToObj(receiver)->data[index] = oop;
  2231. }
  2232.  
  2233. static void storeMethodTemporary(index, oop)
  2234. int    index;
  2235. OOP    oop;
  2236. {
  2237.   prepareToStore(thisContextOOP, oop);
  2238.   temporaries[index] = oop;
  2239. }
  2240.  
  2241. static void storeMethodVariable(methodOOP, index, oop)
  2242. OOP    methodOOP, oop;
  2243. int    index;
  2244. {
  2245.   Method    method = (Method)oopToObj(methodOOP);
  2246.  
  2247.   setAssociationValue(method->literals[index], oop);
  2248. }
  2249.  
  2250. static void storeMethodLiteral(methodOOP, index, oop)
  2251. OOP    methodOOP, oop;
  2252. int    index;
  2253. {
  2254.   Method    method = (Method)oopToObj(methodOOP);
  2255.  
  2256.   prepareToStore(methodOOP, oop);
  2257.   method->literals[index] = oop;
  2258. }
  2259.  
  2260. static Boolean inBounds(oop, index)
  2261. OOP    oop;
  2262. int    index;
  2263. {
  2264.   Object    obj = oopToObj(oop);
  2265.  
  2266.   return (index >= 0 && index < numOOPs(obj));
  2267. }
  2268. #endif /* ACCESSOR_DEBUGGING */
  2269.  
  2270. MethodHeader getMethodHeaderExt(methodOOP)
  2271. OOP    methodOOP;
  2272. {
  2273.   return (getMethodHeader(methodOOP));
  2274. }
  2275.  
  2276. void storeMethodLiteralExt(methodOOP, index, oop)
  2277. OOP    methodOOP, oop;
  2278. int    index;
  2279. {
  2280.   storeMethodLiteral(methodOOP, index, oop);
  2281. }
  2282.  
  2283. /*
  2284.  *    void storeMethodLiteralNoGC(methodOOP, index, oop)
  2285.  *
  2286.  * Description
  2287.  *
  2288.  *    This routine exists primarily for the binary save/restore code.  Rather
  2289.  *    than adding a test of the garbage collector's state to a very busy
  2290.  *    routine, it's better to create a a clone that doesn't do the prepare to
  2291.  *    store.  If this routine were more complicated, it would make sense to
  2292.  *    do the test in storeMethodLiteral (ala instVarAtPut).
  2293.  *
  2294.  * Inputs
  2295.  *
  2296.  *    methodOOP: 
  2297.  *        A method OOP to set the literal of.
  2298.  *    index : the zero-based index of the literal to set
  2299.  *    oop   : the OOP to store into the method's literal table.
  2300.  *
  2301.  */
  2302. void storeMethodLiteralNoGC(methodOOP, index, oop)
  2303. OOP    methodOOP, oop;
  2304. int    index;
  2305. {
  2306.   Method    method = (Method)oopToObj(methodOOP);
  2307.  
  2308.   method->literals[index] = oop;
  2309. }
  2310.  
  2311. /*
  2312.  *    OOP methodLiteralExt(methodOOP, index)
  2313.  *
  2314.  * Description
  2315.  *
  2316.  *    External accessor routine.  Returns a literal from the given method.
  2317.  *
  2318.  * Inputs
  2319.  *
  2320.  *    methodOOP: 
  2321.  *        A CompiledMethod OOP.
  2322.  *    index : An index into the literals of the method.
  2323.  *
  2324.  * Outputs
  2325.  *
  2326.  *    The literal at index in the CompiledMethod.
  2327.  */
  2328. OOP methodLiteralExt(methodOOP, index)
  2329. OOP    methodOOP;
  2330. int    index;
  2331. {
  2332.   return (methodLiteral(methodOOP, index));
  2333. }
  2334.  
  2335. /*
  2336.  *    Boolean equal(oop1, oop2)
  2337.  *
  2338.  * Description
  2339.  *
  2340.  *    Internal definition of equality.  Returns true if "oop1" and "oop2" are
  2341.  *    the same object, false if they are not, and false and an error if they
  2342.  *    are not the same and not both Symbols.
  2343.  *
  2344.  * Inputs
  2345.  *
  2346.  *    oop1  : An OOP to be compared, typically a Symbol.
  2347.  *    oop2  : An OOP to be compared, typically a Symbol.
  2348.  *
  2349.  * Outputs
  2350.  *
  2351.  *    True if the two objects are the same object, false if not, and an error
  2352.  *    message if they are not the same and not both symbols.
  2353.  */
  2354. Boolean equal(oop1, oop2)
  2355. OOP    oop1, oop2;
  2356. {
  2357.   if (oop1 == oop2) {
  2358.     /* no brain case (ha ha ha) */
  2359.     return (true);
  2360.   }
  2361.  
  2362.   if (isClass(oop1, symbolClass) && isClass(oop2, symbolClass)) {
  2363.     return (false);
  2364.   }
  2365.  
  2366.   errorf("Internal #= called with invalid object types\n");
  2367.   return (false);
  2368. }
  2369.  
  2370. /*
  2371.  *    long hash(oop)
  2372.  *
  2373.  * Description
  2374.  *
  2375.  *    Internal hash function.  Currently defined only for symbols, but may be
  2376.  *    extended as needed for other objects.  The definition of the hash
  2377.  *    function used here must be the same as that defined in Smalltalk
  2378.  *    methods.
  2379.  *
  2380.  * Inputs
  2381.  *
  2382.  *    oop   : An OOP to be hashed.
  2383.  *
  2384.  * Outputs
  2385.  *
  2386.  *    Hash value of the OOP, or 0 and an error message if the OOP does not
  2387.  *    have a defined has value (that this routine knows how to compute).
  2388.  */
  2389. long hash(oop)
  2390. OOP    oop;
  2391. {
  2392.   if (!isInt(oop) && oopClass(oop) == symbolClass) {
  2393.     return (oopIndex(oop));
  2394.   }
  2395.  
  2396.   errorf("Internal #hash called with invalid object type\n");
  2397.   return (0);
  2398. }
  2399.  
  2400. #define intBinOp(operator) \
  2401.     oop2 = popOOP();                \
  2402.     oop1 = popOOP();                \
  2403.     if (isInt(oop1) && isInt(oop2)) {        \
  2404.       arg1 = toInt(oop1);            \
  2405.       arg2 = toInt(oop2);            \
  2406.                         \
  2407.       /* could be faster without converting */    \
  2408.       pushInt(arg1 operator arg2);        \
  2409.       return (false);                \
  2410.     }                        \
  2411.     unPop(2);                    \
  2412.     return (true)
  2413.  
  2414. #define boolBinOp(operator)            \
  2415.     oop2 = popOOP();                \
  2416.     oop1 = popOOP();                \
  2417.     if (isInt(oop1) && isInt(oop2)) {        \
  2418.       arg1 = toInt(oop1);            \
  2419.       arg2 = toInt(oop2);            \
  2420.                         \
  2421.       /* could be faster without converting */    \
  2422.       pushBoolean(arg1 operator arg2);        \
  2423.       return (false);                \
  2424.     }                        \
  2425.     unPop(2);                    \
  2426.     return (true)
  2427.  
  2428. /*
  2429.  *    static Boolean executePrimitiveOperation(primitive, numArgs, methodOOP)
  2430.  *
  2431.  * Description
  2432.  *
  2433.  *    This routine provides the definitions of all of the primitive methods
  2434.  *    in the GNU Smalltalk system.  It normally removes the arguments to the
  2435.  *    primitive methods from the stack, but if the primitive fails, the
  2436.  *    arguments are put back onto the stack and this routine returns false,
  2437.  *    indicating failure to invoke the primitive.
  2438.  *
  2439.  * Inputs
  2440.  *
  2441.  *    primitive: 
  2442.  *        A C int that indicates the number of the primitive to invoke.
  2443.  *        Must be > 0.
  2444.  *    numArgs: 
  2445.  *        The number of arguments that the primitive has.
  2446.  *    methodOOP: 
  2447.  *        The OOP for the currently executing method.  This allows
  2448.  *        primitives to poke around in the method itself, to get at
  2449.  *        pieces that they need.  Normally, this is only used by the C
  2450.  *        callout routine to get at the compiled-in descriptor for the
  2451.  *        called C function.
  2452.  *
  2453.  * Outputs
  2454.  *
  2455.  *    True if the execution of the primitive operation succeeded, false if it
  2456.  *    failed for some reason.
  2457.  */
  2458. static Boolean executePrimitiveOperation(primitive, numArgs, methodOOP)
  2459. int    primitive, numArgs;
  2460. OOP    methodOOP;
  2461. {
  2462.   Boolean    failed, atEof, *boolAddr;
  2463.   OOP        oop, oop1, oop2, oop3, oop4, oopVec[4], classOOP, fileOOP,
  2464.         blockContextOOP, stringOOP;
  2465.   long        arg1, arg2, arg3, arg4;
  2466.   double    farg1, farg2, fdummy;
  2467.   int        i, ch;
  2468.   BlockContext    blockContext;
  2469.   Byte        *fileName, *fileMode, *realFileName;
  2470.   FILE        *file;
  2471.   FileStream    fileStream;
  2472.   Semaphore    sem;
  2473.   CObject    cObject;
  2474.   CType        cType;
  2475. #ifdef old_code /* Sat Jan 19 14:40:09 1991 */
  2476. /**/#if !defined(USG)
  2477. /**/  struct timeval tv;
  2478. /**/#else
  2479. /**/  time_t tv;
  2480. /**/#endif
  2481. #endif /* old_code Sat Jan 19 14:40:09 1991 */
  2482.   struct stat    statBuf;
  2483. #ifdef preserved /* Sun Jul 28 14:36:02 1991 */
  2484. /**/#ifdef LOCAL_REGS
  2485. /**/  register OOP    *sp;
  2486. /**/#endif /* LOCAL_REGS */
  2487. #endif /* preserved Sun Jul 28 14:36:02 1991 */
  2488. #undef importSP
  2489. #undef exportSP
  2490. #define importSP()
  2491. #define exportSP()
  2492.   importSP();
  2493.  
  2494. #ifdef countingByteCodes
  2495.   primitives[primitive]++;
  2496. #endif
  2497.  
  2498.   failed = true;
  2499.   switch (primitive) {
  2500.   case 1: intBinOp(+);
  2501.   case 2: intBinOp(-);
  2502.   case 3: boolBinOp(<);
  2503.   case 4: boolBinOp(>);
  2504.   case 5: boolBinOp(<=);
  2505.   case 6: boolBinOp(>=);
  2506.   case 7: boolBinOp(==);
  2507.   case 8: boolBinOp(!=);
  2508.   case 9: intBinOp(*);
  2509.   case 10:
  2510.     oop2 = popOOP();
  2511.     oop1 = popOOP();
  2512.     if (isInt(oop1) && isInt(oop2)) {
  2513.       arg1 = toInt(oop1);
  2514.       arg2 = toInt(oop2);
  2515.       if (arg2 != 0 && (arg1 % arg2) == 0) { /* ### fix this when coercing goes in */
  2516.     /* Uncommented test (arg1 % arg2) to handle fractions davidd. */
  2517.     pushInt(arg1 / arg2);
  2518.     return (false);
  2519.       }
  2520.     }
  2521.     unPop(2);
  2522.     return (true);
  2523.  
  2524.   case 11:
  2525.     oop2 = popOOP();
  2526.     oop1 = popOOP();
  2527.     if (isInt(oop1) && isInt(oop2)) {
  2528.       arg1 = toInt(oop1);
  2529.       arg2 = toInt(oop2);
  2530.       if (arg2 != 0) {
  2531.     if ((arg1 ^ arg2) < 0) {
  2532.       /* ??? help...is there a better way to do this? */
  2533.       pushInt(arg1 - ((arg1 - (arg2-1)) / arg2) * arg2);
  2534.       return (false);
  2535.     } else {
  2536.       pushInt(arg1 % arg2);
  2537.       return (false);
  2538.     }
  2539.       }
  2540.     }
  2541.     unPop(2);
  2542.     return (true);
  2543.  
  2544.   case 12:
  2545.     oop2 = popOOP();
  2546.     oop1 = popOOP();
  2547.     if (isInt(oop1) && isInt(oop2)) {
  2548.       arg1 = toInt(oop1);
  2549.       arg2 = toInt(oop2);
  2550.       if (arg2 != 0) {
  2551.     if ((arg1 ^ arg2) < 0) { /* differing signs => negative result */
  2552.       pushInt((arg1 - (arg2-1)) / arg2);
  2553.       return (false);
  2554.     } else {
  2555.       pushInt(arg1 / arg2);
  2556.       return (false);
  2557.     }
  2558.       }
  2559.     }
  2560.     unPop(2);
  2561.     return (true);
  2562.  
  2563.   case 13:
  2564.     oop2 = popOOP();
  2565.     oop1 = popOOP();
  2566.     if (isInt(oop1) && isInt(oop2)) {
  2567.       arg1 = toInt(oop1);
  2568.       arg2 = toInt(oop2);
  2569.       if (arg2 != 0) {
  2570.     pushInt(arg1 / arg2);
  2571.     return (false);
  2572.       }
  2573.     }
  2574.     unPop(2);
  2575.     return (true);
  2576.  
  2577.   case 14: intBinOp(&);
  2578.   case 15: intBinOp(|);
  2579.   case 16: intBinOp(^);
  2580.   case 17:
  2581.     oop2 = popOOP();
  2582.     oop1 = popOOP();
  2583.     if (isInt(oop1) && isInt(oop2)) {
  2584.       arg1 = toInt(oop1);
  2585.       arg2 = toInt(oop2);
  2586.       if (arg2 >= 0) {
  2587.     pushInt(arg1 << arg2);
  2588.       } else {
  2589.     pushInt(arg1 >> -arg2);
  2590.       }
  2591.       return (false);
  2592.     }
  2593.     unPop(2);
  2594.     return (true);
  2595.  
  2596. #ifdef bogus /* Sat Jan  5 13:46:47 1991 */
  2597. /**/  /*case 1: case  2: case  3: case  4:
  2598. /**/  case  5: case  6: case  7: case  8:
  2599. /**/  case  9: case 10: case 11: case 12:
  2600. /**/  case 13: case 14: case 15: case 16:
  2601. /**/  case 17: */
  2602. /**/    oop2 = popOOP();
  2603. /**/    oop1 = popOOP();
  2604. /**/    if (isInt(oop1) && isInt(oop2)) {
  2605. /**/      failed = false;
  2606. /**/      arg1 = toInt(oop1);
  2607. /**/      arg2 = toInt(oop2);
  2608. /**/      /* ??? make this faster by not pushing and popping */
  2609. /**/
  2610. /**/      switch(primitive) {
  2611. /**//*      case 1:    pushInt(arg1 + arg2);        break; */
  2612. /**//*      case 2:    pushInt(arg1 - arg2);        break; */
  2613. /**//*      case 3:    pushBoolean(arg1 < arg2);    break; */
  2614. /**//*      case 4:    pushBoolean(arg1 > arg2);    break; */
  2615. /**//*      case 5:    pushBoolean(arg1 <= arg2);    break; */
  2616. /**//*      case 6:    pushBoolean(arg1 >= arg2);    break; */
  2617. /**//*      case 7:    pushBoolean(arg1 == arg2);    break; */
  2618. /**//*      case 8:    pushBoolean(arg1 != arg2);    break; */
  2619. /**//*      case 9:    pushInt(arg1 * arg2);        break; /* ### overflow? */
  2620. /**/      case 10:
  2621. /**/    if (arg2 != 0 && (arg1 % arg2) == 0) { /* ### fix this when coercing goes in */
  2622. /**/      /* Uncommented test (arg1 % arg2) to handle fractions davidd. */
  2623. /**/      pushInt(arg1 / arg2);
  2624. /**/    } else {
  2625. /**/      failed = true;
  2626. /**/    }
  2627. /**/    break;
  2628. /**/      case 11:
  2629. /**/    if (arg2 != 0) {
  2630. /**/      if ((arg1 ^ arg2) < 0) {
  2631. /**/        /* ??? help...is there a better way to do this? */
  2632. /**/        pushInt(arg1 - ((arg1 - (arg2-1)) / arg2) * arg2);
  2633. /**/      } else {
  2634. /**/        pushInt(arg1 % arg2);
  2635. /**/      }
  2636. /**/    } else {
  2637. /**/      failed = true;
  2638. /**/    }
  2639. /**/    break;
  2640. /**/      case 12:
  2641. /**/    if (arg2 != 0) {
  2642. /**/      if ((arg1 ^ arg2) < 0) { /* differing signs => negative result */
  2643. /**/        pushInt((arg1 - (arg2-1)) / arg2);
  2644. /**/      } else {
  2645. /**/        pushInt(arg1 / arg2);
  2646. /**/      }
  2647. /**/    } else {
  2648. /**/      failed = true;
  2649. /**/    }
  2650. /**/    break;
  2651. /**/      case 13:
  2652. /**/    if (arg2 != 0) {
  2653. /**/      pushInt(arg1 / arg2);
  2654. /**/    } else {
  2655. /**/      failed = true;
  2656. /**/    }
  2657. /**/    break;
  2658. /**//*      case 14:    pushInt(arg1 & arg2);          break; */
  2659. /**//*      case 15:    pushInt(arg1 | arg2);        break; */
  2660. /**//*      case 16:    pushInt(arg1 ^ arg2);        break; */
  2661. /**/      case 17:
  2662. /**/    /* ??? check for overflow */
  2663. /**/    if (arg2 >= 0) {
  2664. /**/      pushInt(arg1 << arg2);
  2665. /**/    } else {
  2666. /**/      pushInt(arg1 >> -arg2);
  2667. /**/    }
  2668. /**/    break;
  2669. /**/      }
  2670. /**/    }
  2671. /**/
  2672. /**/    if (failed) {
  2673. /**/      unPop(2);
  2674. /**/    }
  2675. /**/    break;
  2676. #endif /* bogus Sat Jan  5 13:46:47 1991 */
  2677.  
  2678.   case 40:
  2679.     oop1 = popOOP();
  2680.     if (isInt(oop1)) {
  2681.       pushOOP(floatNew((double)toInt(oop1)));
  2682.       return (false);
  2683.     }
  2684.     unPop(1);
  2685.     return (true);
  2686.  
  2687.   case 41: case 42: case 43: case 44:
  2688.   case 45: case 46: case 47: case 48:
  2689.   case 49: case 50:
  2690.     oop2 = popOOP();
  2691.     oop1 = popOOP();
  2692.     if (isClass(oop1, floatClass) && isClass(oop2, floatClass)) {
  2693.       failed = false;
  2694.       farg1 = floatOOPValue(oop1);
  2695.       farg2 = floatOOPValue(oop2);
  2696.       switch (primitive) {
  2697.       case 41:    pushOOP(floatNew(farg1 + farg2));    break;
  2698.       case 42:    pushOOP(floatNew(farg1 - farg2));    break;
  2699.       case 43:    pushBoolean(farg1 < farg2);         break;
  2700.       case 44:    pushBoolean(farg1 > farg2);        break;
  2701.       case 45:    pushBoolean(farg1 <= farg2);        break;
  2702.       case 46:    pushBoolean(farg1 >= farg2);        break;
  2703.       case 47:    pushBoolean(farg1 == farg2);        break;
  2704.       case 48:    pushBoolean(farg1 != farg2);        break;
  2705.       case 49:    pushOOP(floatNew(farg1 * farg2));    break;
  2706.       case 50:
  2707.     if (farg2 != 0.0) {
  2708.       pushOOP(floatNew(farg1 / farg2));
  2709.     } else {
  2710.       failed = true;
  2711.     }
  2712.     break;
  2713.       }
  2714.     }
  2715.  
  2716.     if (failed) {
  2717.       unPop(2);
  2718.     }
  2719.     break;
  2720.  
  2721.   case 51:            /* Float truncated */
  2722.     oop1 = popOOP();
  2723.     if (isClass(oop1, floatClass)) {
  2724.       pushInt(/* 0 + ?why?*/(long)floatOOPValue(oop1));
  2725.       return (false);
  2726.     }
  2727.     unPop(1);
  2728.     return (true);
  2729.  
  2730.   case 52:            /* Float fractionPart */
  2731.     oop1 = popOOP();
  2732.     if (isClass(oop1, floatClass)) {
  2733.       farg1 = floatOOPValue(oop1);
  2734.       if (farg1 < 0.0) {
  2735.     farg1 = -farg1;
  2736.       }
  2737.       pushOOP(floatNew(modf(farg1, &fdummy)));
  2738.       return (false);
  2739.     } 
  2740.     unPop(1);
  2741.     return (true);
  2742.  
  2743.   case 53:            /* Float exponent */
  2744.     oop1 = popOOP();
  2745.     if (isClass(oop1, floatClass)) {
  2746.       farg1 = floatOOPValue(oop1);
  2747.       if (farg1 == 0.0) {
  2748.     arg1 = 1;
  2749.       } else {
  2750.     frexp(floatOOPValue(oop1), (int *)&arg1);
  2751.       }
  2752.       pushInt(arg1-1);
  2753.       return (false);
  2754.     }
  2755.     unPop(1);
  2756.     return (true);
  2757.  
  2758.   case 54:            /* Float timesTwoPower: */
  2759.     oop2 = popOOP();
  2760.     oop1 = popOOP();
  2761.     if (isClass(oop1, floatClass) && isInt(oop2)) {
  2762.       farg1 = floatOOPValue(oop1);
  2763.       arg2 = toInt(oop2);
  2764. #ifdef SUNOS40
  2765.       pushOOP(floatNew(scalbn(farg1, arg2)));
  2766. #else
  2767.       pushOOP(floatNew(ldexp(farg1, arg2)));
  2768. #endif
  2769.       return (false);
  2770.     }
  2771.     unPop(2);
  2772.     return (true);
  2773.  
  2774.   case 60:            /* Object at:, Object basicAt: */
  2775.     oop2 = popOOP();
  2776.     oop1 = stackTop();
  2777.     if (isInt(oop2)) {
  2778.       arg2 = toInt(oop2);
  2779.       if (checkIndexableBoundsOf(oop1, arg2)) {
  2780.     setStackTop(indexOOP(oop1, arg2));
  2781.     return (false);
  2782.       }
  2783.     }
  2784.     unPop(1);
  2785.     return (true);
  2786.  
  2787.   case 61:            /* Object at:put:, Object basicAt:put: */
  2788.     oop3 = popOOP();
  2789.     oop2 = popOOP();
  2790.     oop1 = stackTop();
  2791.     if (isInt(oop2)) {
  2792.       arg2 = toInt(oop2);
  2793.       if (checkIndexableBoundsOf(oop1, arg2)) {
  2794.     if (indexOOPPut(oop1, arg2, oop3)) {
  2795.       setStackTop(oop3);
  2796.       return (false);
  2797.     }
  2798.       }
  2799.     }
  2800.  
  2801.     unPop(2);
  2802.     return (true);
  2803.  
  2804.   case 62:            /* Object basicSize; Object size; String size;
  2805.                    ArrayedCollection size */
  2806.     oop1 = popOOP();
  2807.     pushInt(numIndexableFields(oop1));
  2808.     return (false);
  2809.  
  2810.   case 63:            /* String at:; String basicAt: */
  2811.     oop2 = popOOP();
  2812.     oop1 = stackTop();
  2813.     if (isInt(oop2)) {
  2814.       arg2 = toInt(oop2);
  2815.       if (checkIndexableBoundsOf(oop1, arg2)) {
  2816.     setStackTop(indexStringOOP(oop1, arg2));
  2817.     return (false);
  2818.       }
  2819.     }
  2820.  
  2821.     unPop(1);
  2822.     return (true);
  2823.  
  2824.   case 64:            /* String basicAt:put:; String at:put: */
  2825.     oop3 = popOOP();
  2826.     oop2 = popOOP();
  2827.     oop1 = stackTop();
  2828.     if (isInt(oop2) && isClass(oop3, charClass)) {
  2829.       arg2 = toInt(oop2);
  2830.       if (checkIndexableBoundsOf(oop1, arg2)) {
  2831.     indexStringOOPPut(oop1, arg2, oop3);
  2832.     setStackTop(oop3);
  2833.     return (false);
  2834.       }
  2835.     }
  2836.  
  2837.     unPop(2);
  2838.     return (true);
  2839.  
  2840.   case 68:            /* CompiledMethod objectAt: */
  2841.     oop2 = popOOP();
  2842.     oop1 = stackTop();
  2843.     if (isClass(oop1, compiledMethodClass) && isInt(oop2)) {
  2844.       arg2 = toInt(oop2);
  2845.       if (validMethodIndex(oop1, arg2)) {
  2846.     setStackTop(compiledMethodAt(oop1, arg2));
  2847.     return (false);
  2848.       }
  2849.     }
  2850.  
  2851.     unPop(1);
  2852.     return (true);
  2853.  
  2854.   case 69:            /* CompiledMethod objectAt:put: */
  2855.     oop3 = popOOP();
  2856.     oop2 = popOOP();
  2857.     oop1 = stackTop();
  2858.     if (isClass(oop1, compiledMethodClass) && isInt(oop2)) {
  2859.       arg2 = toInt(oop2);
  2860.       if (validMethodIndex(oop1, arg2)) {
  2861.     compiledMethodAtPut(oop1, arg2, oop3);
  2862.     return (false);
  2863.       }
  2864.     }
  2865.  
  2866.     unPop(2);
  2867.     return (true);
  2868.  
  2869.   case 70:            /* Behavior basicNew; Behavior new;
  2870.                    Interval class new */
  2871.     oop1 = stackTop();
  2872.     if (isOOP(oop1)) {
  2873.       if (!isIndexable(oop1)) {
  2874.     setStackTop(allocOOP(instantiate(oop1)));
  2875.     return (false);
  2876.       }
  2877.     }
  2878.     return (true);
  2879.  
  2880.   case 71:            /* Behavior new:; Behavior basicNew: */
  2881.     oop2 = popOOP();
  2882.     oop1 = stackTop();
  2883.     if (isOOP(oop1) && isInt(oop2)) {
  2884.       if (isIndexable(oop1)) {
  2885.     arg2 = toInt(oop2);
  2886.     setStackTop(instantiateOOPWith(oop1, arg2));
  2887.     return (false);
  2888.       }
  2889.     }
  2890.  
  2891.     unPop(1);
  2892.     return (true);
  2893.  
  2894.   case 72:            /* Object become: */
  2895.     oop2 = popOOP();
  2896.     oop1 = stackTop();
  2897.     if (isOOP(oop1) && isOOP(oop2)) {
  2898.       swapObjects(oop1, oop2);
  2899.       setStackTop(oop1);    /* probably not necessary */
  2900.       return (false);
  2901.     }
  2902.     unPop(1);
  2903.     return (true);
  2904.  
  2905.   case 73:            /* Object instVarAt: */
  2906.     oop2 = popOOP();
  2907.     oop1 = stackTop();
  2908.     if (isInt(oop2)) {
  2909.       arg2 = toInt(oop2);
  2910.       if (checkBoundsOf(oop1, arg2)) {
  2911.     setStackTop(instVarAt(oop1, arg2));
  2912.     return (false);
  2913.       }
  2914.     }
  2915.     unPop(1);
  2916.     return (true);
  2917.  
  2918.   case 74:            /* Object instVarAt:put: */
  2919.     oop3 = popOOP();
  2920.     oop2 = popOOP();
  2921.     oop1 = stackTop();
  2922.     if (isInt(oop2)) {
  2923.       arg2 = toInt(oop2);
  2924.       if (checkBoundsOf(oop1, arg2)) {
  2925.     if (instVarAtPut(oop1, arg2, oop3)) {
  2926.       return (false);
  2927.     }
  2928.       }
  2929.     }
  2930.     unPop(2);
  2931.     return (true);
  2932.  
  2933.   case 75:            /* Object asOop; Object hash; Symbol hash */
  2934.     oop1 = popOOP();
  2935.     if (isOOP(oop1)) {
  2936.       pushInt(oopIndex(oop1));
  2937.       return (false);
  2938.     }
  2939.     unPop(1);
  2940.     return (true);
  2941.  
  2942.   case 76:            /* SmallInteger asObject;
  2943.                    SmallInteger asObjectNoFail */
  2944.     oop1 = stackTop();
  2945.     if (isInt(oop1)) {        /* redundant? */
  2946.       arg1 = toInt(oop1);
  2947.       if (oopIndexValid(arg1)) {
  2948.     setStackTop(oopAt(arg1-1));
  2949.     return (false);
  2950.       }
  2951.     }
  2952.  
  2953.     return (true);
  2954.  
  2955.   case 77:            /* Behavior someInstance */
  2956.     oop1 = stackTop(); 
  2957.     for (oop = oopTable; oop < &oopTable[TOTAL_OOP_TABLE_SLOTS]; oop++) {
  2958.       if (oopValid(oop) && oop1 == oopClass(oop)) {
  2959.     setStackTop(oop);
  2960.     return (false);
  2961.       }
  2962.     }
  2963.     return (true);
  2964.  
  2965.   case 78:            /* Object nextInstance */
  2966.     oop1 = stackTop();
  2967.     if (!isInt(oop1)) {
  2968.       classOOP = oopClass(oop1);
  2969.       for (oop = oop1 + 1; oop < &oopTable[TOTAL_OOP_TABLE_SLOTS]; oop++) {
  2970.     if (oopValid(oop) && classOOP == oopClass(oop)) {
  2971.       setStackTop(oop);
  2972.       return (false);
  2973.     }
  2974.       }
  2975.     }
  2976.     return (true);
  2977.  
  2978.   case 79:            /* CompiledMethod class newMethod:header: */
  2979.     oop3 = popOOP();
  2980.     oop2 = popOOP();
  2981.     oop1 = stackTop();
  2982.     if (isInt(oop3) && isInt(oop2)) {
  2983.       arg3 = toInt(oop3);
  2984.       arg2 = toInt(oop2);
  2985.       setStackTop(methodNewOOP(arg2, arg3));
  2986.       return (false);
  2987.     }
  2988.     unPop(2);
  2989.     return (true);
  2990.  
  2991.   case 80:            /* ContextPart blockCopy: */
  2992.     oop2 = popOOP();
  2993.     oop1 = stackTop();
  2994.     if (isInt(oop2)) {
  2995.       arg2 = toInt(oop2);
  2996.       blockContextOOP = allocBlockContext();
  2997.       blockContext = (BlockContext)oopToObj(blockContextOOP);
  2998.  if (isFake(getMethodContext(oop1))) {
  2999.    printf("############## Fake in block copy!\n");
  3000.  }
  3001.       blockContext->home = getMethodContext(oop1);
  3002.       maybeMoveOOP(blockContext->home);
  3003.       blockContext->numArgs = oop2;
  3004.       methodHasBlockContext(blockContext->home); /* prob. not necessary */
  3005.       /* the +2 here is to skip over the jump byte codes that follow the
  3006.      invocation of blockCopy, so that the ipIndex points to the first
  3007.      byte code of the block. */
  3008.       blockContext->initialIP = fromInt(relativeByteIndex(ip, thisMethod) + 2);
  3009.       if (oopClass(blockContext->home) != methodContextClass) {
  3010.     errorf("Block's home is not a MethodContext!!!\n");
  3011.       }
  3012.       setStackTop(blockContextOOP);
  3013.       return (false);
  3014.     }
  3015.     unPop(1);
  3016.     return (true);
  3017.  
  3018.   case 81:            /* BlockContext value
  3019.                    BlockContext value:
  3020.                    BlockContext value:value:
  3021.                    BlockContext value:value:value: */
  3022.     exportSP();
  3023.     sendBlockValue(numArgs);    /* ### check number of args for agreement! */
  3024.     importSP();
  3025.     return (false);
  3026.  
  3027.   case 82:            /* BlockContext valueWithArguments: */
  3028.     oop2 = popOOP();
  3029.     oop1 = stackTop();
  3030.     if (isClass(oop2, arrayClass)) {
  3031.       numArgs = numIndexableFields(oop2);
  3032.       for (i = 1; i <= numArgs; i++) {
  3033.     pushOOP(arrayAt(oop2, i));
  3034.       }
  3035.       exportSP();
  3036.       sendBlockValue(numArgs);
  3037.       importSP();
  3038.       return (false);
  3039.     }
  3040.     unPop(1);
  3041.     return (true);
  3042.  
  3043.   case 83:            /* Object perform:
  3044.                    Object perform:with:
  3045.                    Object perform:with:with:
  3046.                    Object perform:with:with:with: */
  3047.     /* pop off the arguments (if any) */
  3048.     for (i = 0; i < numArgs - 1; i++) {
  3049.       oopVec[i] = popOOP();
  3050.     }
  3051.     oop1 = popOOP();        /* the selector */
  3052.     /* push the args back onto the stack */
  3053.     for (; --i >= 0; ) {
  3054.       pushOOP(oopVec[i]);
  3055.     }
  3056.     exportSP();
  3057.     sendMessage(oop1, numArgs - 1, false);
  3058.     importSP();
  3059.     return (false);
  3060.  
  3061.   case 84:            /* Object perform:withArguments: */
  3062.     oop2 = popOOP();
  3063.     oop1 = popOOP();
  3064.     if (isClass(oop2, arrayClass)) {
  3065.       numArgs = numIndexableFields(oop2);
  3066.       for (i = 1; i <= numArgs; i++) {
  3067.     pushOOP(arrayAt(oop2, i));
  3068.       }
  3069.       exportSP();
  3070.       sendMessage(oop1, numArgs, false);
  3071.       importSP();
  3072.       return (false);
  3073.     }
  3074.     unPop(2);
  3075.     return (true);
  3076.  
  3077.   case 85:            /* Semaphore signal */
  3078.     oop1 = stackTop();
  3079.     if (isClass(oop1, semaphoreClass)) {
  3080.       syncSignal(oop1);
  3081.       return (false);
  3082.     }
  3083.     return (true);
  3084.  
  3085.   case 86:            /* Semaphore wait */
  3086.     oop1 = stackTop();
  3087.     if (isClass(oop1, semaphoreClass)) { /* necessary? */
  3088.       sem = (Semaphore)oopToObj(oop1);
  3089.       if (toInt(sem->signals) > 0) {    /* no waiting here */
  3090.     sem->signals = decrInt(sem->signals);
  3091.       } else {            /* have to suspend */
  3092.     addLastLink(oop1, getActiveProcess());
  3093.     suspendActiveProcess();
  3094.       }
  3095.       return (false);
  3096.     }
  3097.     return (true);
  3098.  
  3099.   case 87:            /* Process resume */
  3100.     resumeProcess(stackTop());
  3101.     return (false);
  3102.  
  3103.   case 88:            /* Process suspend */
  3104.     oop1 = stackTop();
  3105.     if (oop1 == getActiveProcess()) {
  3106.       setStackTop(nilOOP);        /* this is our return value */
  3107.       suspendActiveProcess();
  3108.       return (false);
  3109.     }
  3110.     return (true);
  3111.  
  3112.  
  3113.   case 98:            /* Time class secondClock
  3114.                  *  -- note: this primitive has different
  3115.                  *     semantics from those defined in the
  3116.                  *     book.  This primitive returns the
  3117.                  *     seconds since Jan 1, 1970 00:00:00
  3118.                  *     instead of Jan 1,1901.
  3119.                  */
  3120.     popOOP();
  3121.     pushInt(getTime());
  3122. #ifdef old_code /* Sat Jan 19 10:25:40 1991 */
  3123. /**/#if !defined(USG)
  3124. /**/    gettimeofday(&tv, nil);
  3125. /**/    pushInt(tv.tv_sec);
  3126. /**/#else
  3127. /**/    (void) time(&tv);
  3128. /**/    pushInt(tv);
  3129. /**/#endif
  3130. #endif /* old_code Sat Jan 19 10:25:40 1991 */
  3131.     return (false);
  3132.  
  3133.   case 99:            /* Time class millisecondClock
  3134.                  * -- Note: the semantics of this primitive
  3135.                  *    are different than those described in
  3136.                  *    the book.  This primitive returns the
  3137.                  *    number of milliseconds since midnight
  3138.                  *    today. */
  3139.     popOOP();
  3140.     pushInt(getMilliTime() % (24*60*60*1000));
  3141. #ifdef old_code /* Sat Jan 19 10:26:01 1991 */
  3142. /**/#if !defined(USG)
  3143. /**/    gettimeofday(&tv, nil);
  3144. /**/    pushInt((tv.tv_sec % (24*60*60)) * 1000 + tv.tv_usec / 1000);
  3145. /**/#else
  3146. /**/    (void) time(&tv);
  3147. /**/    pushInt((tv % (24*60*60)) * 1000);
  3148. /**/#endif
  3149. #endif /* old_code Sat Jan 19 10:26:01 1991 */
  3150.     return (false);
  3151.  
  3152.   case 100:            /* Processor signal: semaphore
  3153.                  *           atMilliseconds: deltaMilliseconds
  3154.                      */
  3155.     oop2 = popOOP();
  3156.     oop1 = popOOP();
  3157.     if (isInt(oop2)) {
  3158.       arg2 = toInt(oop2);
  3159.       timeoutSem = oop1;
  3160.       signalAfter(arg2, timeoutHandler);
  3161.       return (false);
  3162.     }
  3163.  
  3164.     unPop(2);
  3165.     return (true);
  3166.  
  3167.   case 105:            /* ByteArray primReplaceFrom:to:with:startingAt
  3168.                  * ByteArray replaceFrom:to:withString:startingAt:
  3169.                  * String replaceFrom:to:withByteArray:startingAt:
  3170.                  * String primReplaceFrom:to:with:startingAt:*/
  3171.     {
  3172.       OOP    srcIndexOOP, srcOOP, dstEndIndexOOP, dstStartIndexOOP, dstOOP;
  3173.       int    dstEndIndex, dstStartIndex, srcIndex, dstLen, srcLen,
  3174.               dstRangeLen;
  3175.       Byte    *dstBase, *srcBase;
  3176.  
  3177.       srcIndexOOP = popOOP();
  3178.       srcOOP = popOOP();
  3179.       dstEndIndexOOP = popOOP();
  3180.       dstStartIndexOOP = popOOP();
  3181.       if (isInt(srcIndexOOP) && isInt(dstStartIndexOOP)
  3182.       && isInt(dstEndIndexOOP)) {
  3183.     if (isAKindOf(oopClass(srcOOP), byteArrayClass)
  3184.         || isAKindOf(oopClass(srcOOP), stringClass)) {
  3185.       /* dstEnd is inclusive: (1 to: 1) has length 1 */
  3186.       dstEndIndex = toInt(dstEndIndexOOP);
  3187.       dstStartIndex = toInt(dstStartIndexOOP);
  3188.       srcIndex = toInt(srcIndexOOP);
  3189.       dstOOP = stackTop();
  3190.       dstLen = numIndexableFields(dstOOP);
  3191.       srcLen = numIndexableFields(srcOOP);
  3192.       dstRangeLen = dstEndIndex - dstStartIndex + 1;
  3193.       if ((dstRangeLen >= 0 && dstEndIndex <= dstLen
  3194.            && dstStartIndex > 0)) {
  3195.         if (dstRangeLen > 0) { /* don't do it unless somethings to copy */
  3196.           if ((srcIndex <= srcLen) && (srcIndex > 0)
  3197.           && (srcIndex + dstRangeLen - 1 <= srcLen)) {
  3198.         /* do the copy */
  3199.         dstBase = stringOOPChars(dstOOP);
  3200.         srcBase = stringOOPChars(srcOOP);
  3201.         memcpy(&dstBase[dstStartIndex-1], &srcBase[srcIndex-1],
  3202.                dstRangeLen);
  3203.           }
  3204.         }
  3205.         return (false);
  3206.       }
  3207.     }
  3208.       }
  3209.     
  3210.       unPop(4);
  3211.       return (true);
  3212.     }
  3213.  
  3214.   case 110:            /* Object ==, Character = */
  3215.     oop2 = popOOP();
  3216.     oop1 = popOOP();
  3217.     pushBoolean(oop1 == oop2);
  3218.     return (false);
  3219.  
  3220.   case 111:            /* Object class */
  3221.     oop1 = popOOP();
  3222.     /* ??? is this called with ints? */
  3223.     if (isInt(oop1)) {
  3224.       pushOOP(integerClass);
  3225.     } else {
  3226.       pushOOP(oopClass(oop1));
  3227.     }
  3228.     return (false);
  3229.  
  3230.   case 113:            /* quitPrimitive */
  3231.     exit(0);
  3232.     break;            /* This does nothing :-) */
  3233.  
  3234.   case 117:            /* quitPrimitive: status */
  3235.     oop1 = stackTop();
  3236.     if (isInt(oop1)) {
  3237.       arg1 = toInt(oop1);
  3238.       exit(arg1);
  3239.     }
  3240.     return (true);
  3241.  
  3242. /* ------- GNU Smalltalk specific primitives begin here -------------------- */
  3243.  
  3244.   case 128:            /* Dictionary at: */
  3245.     oop2 = popOOP();
  3246.     oop1 = stackTop();
  3247.     setStackTop(dictionaryAt(oop1, oop2));
  3248.     return (false);
  3249.  
  3250.   case 129:            /* Dictionary at: put: */
  3251.     oop3 = popOOP();
  3252.     oop2 = popOOP();
  3253.     oop1 = stackTop();
  3254.     dictionaryAtPut(oop1, oop2, oop3);
  3255.     setStackTop(oop3);
  3256.     return (false);
  3257.  
  3258.   case 130:            /* doesNotUnderstand: message */
  3259.     oop2 = popOOP();
  3260.     oop1 = popOOP();
  3261.     printObject(oop1);
  3262.     printf(" did not understand selector '");
  3263.     printSymbol(messageSelector(oop2));
  3264.     printf("'\n\n");
  3265.     showBacktrace();
  3266.     stopExecuting(0);
  3267.     return (false);
  3268.  
  3269.   case 131:            /* error: message */
  3270.     oop2 = popOOP();        /* error string */
  3271.     oop1 = stackTop();        /* the receiver */
  3272.     printObject(oop1);
  3273.     printf(" error: ");
  3274.     printString(oop2);
  3275.     printf("\n\n");
  3276.     showBacktrace();
  3277.     stopExecuting(0);
  3278.     return (false);
  3279.     
  3280.   case 132:            /* Character class value: */
  3281.     oop2 = popOOP();
  3282.     oop1 = stackTop();
  3283.     if (isInt(oop2)) {
  3284.       arg2 = toInt(oop2);
  3285.       if (arg2 >= 0 && arg2 <= 255) {
  3286.     setStackTop(charOOPAt(arg2));
  3287.     return (false);
  3288.       }
  3289.     }
  3290.     unPop(1);
  3291.     return (true);
  3292.  
  3293.   case 133:            /* Character asciiValue */
  3294.     oop1 = popOOP();
  3295.     pushInt(charOOPValue(oop1));
  3296.     return (false);
  3297.  
  3298.   case 134:            /* Symbol class intern: aString */
  3299.     oop2 = popOOP();
  3300.     oop1 = stackTop();
  3301.     if (isClass(oop2, stringClass)) {
  3302.       setStackTop(internStringOOP(oop2));
  3303.       return (false);
  3304.     }
  3305.     unPop(1);
  3306.     return (true);
  3307.  
  3308.   case 135:            /* Dictionary new */
  3309.     setStackTop(dictionaryNew());
  3310.     return (false);
  3311.  
  3312.   case 136:            /* ByteMemory at: */
  3313.     oop2 = popOOP();
  3314.     oop1 = popOOP();
  3315.     if (isInt(oop2)) {
  3316.       arg2 = toInt(oop2);
  3317.       pushInt(*(Byte *)arg2);
  3318.       return (false);
  3319.     }
  3320.     unPop(2);
  3321.     return (true);
  3322.     
  3323.   case 137:            /* ByteMemory at:put: */
  3324.     oop3 = popOOP();
  3325.     oop2 = popOOP();
  3326.     if (isInt(oop2) && isInt(oop3)) {
  3327.       arg1 = toInt(oop2);
  3328.       arg2 = toInt(oop3);
  3329.       if (arg2 >= 0 && arg2 <= 255) {
  3330.     *(Byte *)arg1 = arg2;
  3331.     return (false);
  3332.       }
  3333.     }
  3334.     unPop(2);
  3335.     return (true);
  3336.     
  3337.   case 138:            /* Memory addressOfOOP: oop */
  3338.     oop2 = popOOP();
  3339.     oop1 = popOOP();
  3340.     if (!isInt(oop2)) {
  3341.       pushInt((long)oop2);
  3342.       return (false);
  3343.     }
  3344.     unPop(2);
  3345.     return (true);
  3346.  
  3347.   case 139:            /* Memory addressOf: oop */
  3348.     oop2 = popOOP();
  3349.     oop1 = popOOP();
  3350.     if (!isInt(oop2)) {
  3351.       pushInt((long)oopToObj(oop2));
  3352.       return (false);
  3353.     }
  3354.     unPop(2);
  3355.     return (true);
  3356.  
  3357.   case 140:            /* SystemDictionary backtrace */
  3358.     showBacktrace();
  3359.     return (false);
  3360.  
  3361.   case 141:            /* SystemDictionary getTraceFlag: anIndex */
  3362.     oop2 = popOOP();
  3363.     oop1 = popOOP();
  3364.     if (isInt(oop2)) {
  3365.       arg2 = toInt(oop2);
  3366.       boolAddr = boolAddrIndex(arg2);
  3367.       if (boolAddr != NULL) {
  3368.     oop1 = *boolAddr ? trueOOP : falseOOP;
  3369.     pushOOP(oop1);
  3370.     return (false);
  3371.       }
  3372.     }
  3373.  
  3374.     unPop(2);
  3375.     return (true);
  3376.  
  3377.   case 142:            /* SystemDictionary setTraceFlag: anIndex
  3378.                                     to: aBoolean */
  3379.     oop2 = popOOP();
  3380.     oop1 = popOOP();
  3381.     if (isInt(oop1)) {
  3382.       arg1 = toInt(oop1);
  3383.       boolAddr = boolAddrIndex(arg1);
  3384.       if (boolAddr != NULL) {
  3385.     *boolAddr = (oop2 == trueOOP) ? true : false;
  3386.     exceptFlag = true;
  3387.     return (false);
  3388.       }
  3389.     }
  3390.     
  3391.     unPop(2);
  3392.     return (true);
  3393.  
  3394. #ifdef old_code /* Thu Jun  6 15:06:41 1991 */
  3395. /**/  case 141:            /* SystemDictionary executionTrace: aBoolean */
  3396. /**/    oop1 = popOOP();
  3397. /**/    if (oop1 == trueOOP) {
  3398. /**/      executionTracing = true;
  3399. /**/    } else {
  3400. /**/      executionTracing = false;
  3401. /**/    }
  3402. /**/    exceptFlag = true;
  3403. /**/    return (false);
  3404. /**/
  3405. /**/  case 142:            /* SystemDictionary declarationTrace: aBoolean */
  3406. /**/    oop1 = popOOP();
  3407. /**/    if (oop1 == trueOOP) {
  3408. /**/      declareTracing = true;
  3409. /**/    } else {
  3410. /**/      declareTracing = false;
  3411. /**/    }
  3412. /**/    return (false);
  3413. /**/
  3414. #endif /* old_code Thu Jun  6 15:06:41 1991 */
  3415.  
  3416.   case 143:            /* ClassDescription comment: aString */
  3417.     oop2 = popOOP();
  3418.     oop1 = stackTop();
  3419.     setComment(oop1, oop2);
  3420.     return (false);
  3421.  
  3422.   case 144:            /* CObject class alloc: nBytes */
  3423.     oop2 = popOOP();
  3424.     oop1 = stackTop();
  3425.     if (isInt(oop2)) {
  3426.       arg2 = toInt(oop2);
  3427.       setStackTop(allocCObject(oop1, arg2));
  3428.       return (false);
  3429.     }
  3430.     unPop(1);
  3431.     return (true);
  3432.  
  3433.   case 145:            /* Memory (?) type: aType at: anAddress */
  3434.     oop3 = popOOP();
  3435.     oop2 = popOOP();
  3436.     oop1 = popOOP();
  3437.     if (isInt(oop3) && isInt(oop2)) {
  3438.       arg1 = toInt(oop2);
  3439.       arg2 = toInt(oop3);
  3440. /*      failed = false; */
  3441.       switch (arg1) {
  3442.       case 0:            /* char */
  3443.     /* may want to use Character instead? */
  3444.     pushOOP(charOOPAt(*(char *)arg2));
  3445.     return (false);
  3446.       case 1:            /* unsigned char */
  3447.     pushOOP(charOOPAt(*(unsigned char *)arg2));
  3448.     return (false);
  3449.       case 2:            /* short */
  3450.     pushInt(*(short *)arg2);
  3451.     return (false);
  3452.       case 3:            /* unsigned short */
  3453.     pushInt(*(unsigned short *)arg2);
  3454.     return (false);
  3455.       case 4:            /* int */
  3456.     pushInt(*(int *)arg2);
  3457.     return (false);
  3458.       case 5:            /* unsigned int */
  3459.     pushInt(*(unsigned int *)arg2);
  3460.     return (false);
  3461.       case 6:            /* float */
  3462.     pushOOP(floatNew(*(float *)arg2));
  3463.     return (false);
  3464.       case 7:            /* double */
  3465.     pushOOP(floatNew(*(double *)arg2));
  3466.     return (false);
  3467.       case 8:            /* string */
  3468.     if (*(char **)arg2) {
  3469.       pushOOP(stringNew(*(char **)arg2));
  3470.     } else {
  3471.       pushOOP(nilOOP);
  3472.     }
  3473.     return (false);
  3474.       }
  3475.     }
  3476.  
  3477.     unPop(3);
  3478.     return (true);
  3479.  
  3480.  
  3481.   case 146:            /* Memory (?) type: aType at: anAddress
  3482.                    put: aValue */
  3483.     oop4 = popOOP();
  3484.     oop3 = popOOP();
  3485.     oop2 = popOOP();
  3486.     /* don't pop the receiver */
  3487.     if (isInt(oop3) && isInt(oop2)) {
  3488.       arg1 = toInt(oop2);
  3489.       arg2 = toInt(oop3);
  3490.       switch (arg1) {
  3491.       case 0:            /* char */
  3492.       case 1:            /* unsigned char */
  3493.     /* may want to use Character instead? */
  3494.     if (isClass(oop4, charClass)) {
  3495.       *(char *)arg2 = charOOPValue(oop4);
  3496.       return (false);
  3497.     }
  3498.     break;
  3499.       case 2:            /* short */
  3500.       case 3:            /* unsigned short */
  3501.     if (isInt(oop4)) {
  3502.       *(short *)arg2 = toInt(oop4);
  3503.       return (false);
  3504.     }
  3505.     break;
  3506.       case 4:            /* int */
  3507.       case 5:            /* unsigned int */
  3508.     if (isInt(oop4)) {
  3509.       *(int *)arg2 = toInt(oop4);
  3510.       return (false);
  3511.     }
  3512.     break;
  3513.       case 6:            /* float */
  3514.     if (isClass(oop4, floatClass)) {
  3515.       *(float *)arg2 = floatOOPValue(oop4);
  3516.       return (false);
  3517.     }
  3518.     break;
  3519.       case 7:            /* double */
  3520.     if (isClass(oop4, floatClass)) {
  3521.       *(double *)arg2 = floatOOPValue(oop4);
  3522.       return (false);
  3523.     }
  3524.     break;
  3525.       case 8:            /* string */
  3526.     if (isClass(oop4, stringClass) || isClass(oop4, symbolClass)) {
  3527.       (char *)arg2 = (char *)toCString(oop4);
  3528.       return (false);
  3529.     }
  3530.     break;
  3531.       }
  3532.     }
  3533.  
  3534.     unPop(3);
  3535.     return (true);
  3536.  
  3537.  
  3538.   case 147:            /* <CObject> at: offset type: aType */
  3539.     oop3 = popOOP();
  3540.     oop2 = popOOP();
  3541.     oop1 = popOOP();
  3542.  
  3543.     if (isInt(oop2)) {
  3544.       arg2 = toInt(oop2);
  3545.       cObject = (CObject)oopToObj(oop1);
  3546.       arg2 += (unsigned long)cObject->addr;
  3547.       if (isInt(oop3)) {
  3548.     arg3 = toInt(oop3);
  3549.     switch (arg3) {        /* maybe switch to symbolic names sometime */
  3550.     case 0:            /* char */
  3551.       pushOOP(charOOPAt(*(unsigned char *)arg2));
  3552. /*      pushOOP(*(char *)(arg2)); */
  3553.       return (false);
  3554.     case 1:            /* u_char */
  3555.       pushOOP(charOOPAt(*(unsigned char *)arg2));
  3556. /*       pushInt(*(unsigned char *)(arg2)); */
  3557.       return (false);
  3558.     case 2:            /* short */
  3559.       pushInt(*(short *)(arg2));
  3560.       return (false);
  3561.     case 3:            /* u_short */
  3562.       pushInt(*(unsigned short *)(arg2));
  3563.       return (false);
  3564.     case 4:            /* long */
  3565.       pushInt(*(long *)(arg2));
  3566.       return (false);
  3567.     case 5:            /* u_long */
  3568.       pushInt(*(unsigned long *)(arg2));
  3569.       return (false);
  3570.     case 6:            /* float */
  3571.       pushOOP(floatNew(*(float *)(arg2)));
  3572.       return (false);
  3573.     case 7:            /* double */
  3574.       pushOOP(floatNew(*(double *)(arg2)));
  3575.       return (false);
  3576.     case 8:            /* string */
  3577.       if (*(char **)arg2) {
  3578.         pushOOP(stringNew(*(char **)(arg2)));
  3579.         return (false);
  3580.       } else {
  3581.         pushOOP(nilOOP);
  3582.         return (false);
  3583.       }
  3584.     case 9:            /* deref */
  3585.       cType = (CType)oopToObj(cObject->type);
  3586.       pushOOP(
  3587.           cObjectNewTyped((*(unsigned long *)cObject->addr) + toInt(oop2),
  3588.                   cType->subType));
  3589.       return (false);
  3590.     }
  3591.       } else {            /* just a subtype access */
  3592.     pushOOP(cObjectNewTyped(arg2, oop3));
  3593.     return (false);
  3594.       }
  3595.     }
  3596.  
  3597.     unPop(3);
  3598.     return (true);
  3599.     
  3600.   case 148:            /* <CObject> at: offset put: value
  3601.                             type: aType */
  3602.     oop4 = popOOP();
  3603.     oop3 = popOOP();
  3604.     oop2 = popOOP();
  3605.     oop1 = popOOP();
  3606.  
  3607.     if (isInt(oop2)) {
  3608.       arg2 = toInt(oop2);
  3609.       cObject = (CObject)oopToObj(oop1);
  3610.       arg2 += (unsigned long)cObject->addr;
  3611.       if (isInt(oop4)) {
  3612.     arg4 = toInt(oop4);
  3613.     switch (arg4) {        /* maybe switch to symbolic names sometime */
  3614.     case 0:            /* char */
  3615.       if (isClass(oop3, charClass)) {
  3616.         *(char *)arg2 = charOOPValue(oop3);
  3617.         return (false);
  3618.       }
  3619.       break;
  3620.     case 1:            /* u_char */
  3621.       if (isClass(oop3, charClass)) {
  3622.         *(unsigned char *)arg2 = charOOPValue(oop3);
  3623.         return (false);
  3624.       }
  3625.       break;
  3626.     case 2:            /* short */
  3627.       if (isInt(oop3)) {
  3628.         *(short *)arg2 = toInt(oop3);
  3629.         return (false);
  3630.       }
  3631.       break;
  3632.     case 3:            /* u_short */
  3633.       if (isInt(oop3)) {
  3634.         *(unsigned short *)arg2 = toInt(oop3);
  3635.         return (false);
  3636.       }
  3637.       break;
  3638.     case 4:            /* long */
  3639.       if (isInt(oop3)) {
  3640.         *(long *)arg2 = toInt(oop3);
  3641.         return (false);
  3642.       }
  3643.       break;
  3644.     case 5:            /* u_long */
  3645.       if (isInt(oop3)) {
  3646.         *(unsigned long *)arg2 = toInt(oop3);
  3647.         return (false);
  3648.       }
  3649.       break;
  3650.     case 6:            /* float */
  3651.       if (isInt(oop3)) {
  3652.         *(float *)arg2 = toInt(oop3);
  3653.         return (false);
  3654.       } else if (isClass(oop3, floatClass)) {
  3655.         *(float *)arg2 = floatOOPValue(oop3);
  3656.         return (false);
  3657.       } 
  3658.       break;
  3659.     case 7:            /* double */
  3660.       if (isInt(oop3)) {
  3661.         *(double *)arg2 = toInt(oop3);
  3662.         return (false);
  3663.       } else if (isClass(oop3, floatClass)) {
  3664.         *(double *)arg2 = floatOOPValue(oop3);
  3665.         return (false);
  3666.       } 
  3667.       break;
  3668.     case 8:            /* string */
  3669.       if (oop3 == nilOOP) {
  3670.         *(char **)arg2 = (char *)0;
  3671.         return (false);
  3672.       } else {
  3673.         *(char **)arg2 = (char *)toCString(oop3);
  3674.         return (false);
  3675.       }
  3676.     case 9:            /* deref */
  3677.       if (isAKindOf(oopClass(oop3), cObjectClass)) {
  3678.         cObject = (CObject)oopToObj(oop3);
  3679.         *(voidPtr *)arg2 = cObject->addr;
  3680.         pushOOP(cObjectNewTyped((*(unsigned long *)cObject->addr)
  3681.                     + toInt(oop2), oop3));
  3682.         return (false);
  3683.       }
  3684.       break;
  3685.     }
  3686.       } else {            /* just a subtype access */
  3687.     ;            /* don't allow this right now! */
  3688.       }
  3689.     }
  3690.  
  3691.     unPop(4);
  3692.     return (true);
  3693.     
  3694.   case 149:            /* <CObject> type */
  3695.     oop1 = stackTop();
  3696.     
  3697.     if (isAKindOf(oopClass(oop1), cObjectClass)) {
  3698.       cObject = (CObject)oopToObj(oop1);
  3699.       setStackTop(cObject->type);
  3700.       return (false);
  3701.     }
  3702.     return (true);
  3703.     
  3704.   case 150:            /* methodsFor: category */
  3705.     setCompilationCategory(popOOP());
  3706.     setCompilationClass(stackTop());
  3707.     return (false);
  3708.  
  3709.   case 151:            /* methodsFor: category ifTrue: condition */
  3710.     oop2 = popOOP();
  3711.     oop1 = popOOP();
  3712.     if (oop2 == trueOOP) {
  3713.       setCompilationCategory(oop1);
  3714.       setCompilationClass(stackTop());
  3715.     } else {
  3716.       skipCompilation = true;
  3717.     }
  3718.     return (false);
  3719.       
  3720.  
  3721.   case 152:            /* ProcessorScheduler signal: aSemaphore
  3722.                                       onInterrupt: anInteger */
  3723.     oop2 = popOOP();
  3724.     oop1 = popOOP();
  3725.     if (isInt(oop2)) {
  3726.       arg2 = toInt(oop2);
  3727.       semIntVec[arg2] = oop1;
  3728.       signal(arg2, semIntHandler);
  3729.       /* should probably package up the old interrupt state here for return
  3730.        * so that it can be undone */
  3731.       return(false);
  3732.     }
  3733.  
  3734.     unPop(2);
  3735.     return(true);
  3736.  
  3737.   case 153:            /* SystemDictionary spaceGrowRate */
  3738.     setStackTop(floatNew(spaceGrowRate));
  3739.     return (false);
  3740.  
  3741.   case 154:            /* SystemDictionary spaceGrowRate: */
  3742.     oop1 = popOOP();
  3743.     if (isClass(oop1, floatClass)) {
  3744.       farg1 = floatOOPValue(oop1);
  3745.       /* ### want to do some bounds checking here */
  3746.       spaceGrowRate = farg1;
  3747.       return (false);
  3748.     }
  3749.  
  3750.     unPop(2);
  3751.     return (true);
  3752.     
  3753.   case 155:            /* SystemDictionary growThresholdPercent */
  3754.     setStackTop(floatNew(growThresholdPercent));
  3755.     return (false);
  3756.  
  3757.   case 156:            /* SystemDictionary growThresholdPercent: */
  3758.     oop1 = popOOP();
  3759.     if (isClass(oop1, floatClass)) {
  3760.       farg1 = floatOOPValue(oop1);
  3761.       if (farg1 >= 0.0 && farg1 <= 100.0) {
  3762.     growThresholdPercent = farg1;
  3763.     return (false);
  3764.       }
  3765.     }
  3766.  
  3767.     unPop(2);
  3768.     return (true);
  3769.  
  3770.   case 160:            /* exp */
  3771.   case 161:            /* ln */
  3772.     oop1 = stackTop();
  3773.     if (isClass(oop1, floatClass)) {
  3774.       farg1 = floatOOPValue(oop1);
  3775.       switch (primitive) {
  3776.       case 160: setStackTop(floatNew(exp(farg1)));    return (false);
  3777.       case 161: setStackTop(floatNew(log(farg1)));    return (false);
  3778.       }
  3779.     }
  3780.     return (true);
  3781.  
  3782.   /* case 162:            /* log: aNumber -- base aNumber log */
  3783.   /* case 163:            /* floorLog: radix -- integer floor operation */
  3784.  
  3785.   case 164:            /* raisedTo: aNumber -- receiver ** aNumber */
  3786.     oop2 = popOOP();
  3787.     oop1 = stackTop();
  3788.     if (isClass(oop1, floatClass) && isClass(oop2, floatClass)) {
  3789.       farg1 = floatOOPValue(oop1);
  3790.       farg2 = floatOOPValue(oop2);
  3791.       setStackTop(floatNew(pow(farg1, farg2)));
  3792.       return (false);
  3793.     }
  3794.     unPop(1);
  3795.     return (true);
  3796.  
  3797.  
  3798.   /* >>>>>> HOLE 165 <<<<<< */
  3799.  
  3800.   case 166:            /* sqrt -- floating result */
  3801.     oop1 = stackTop();
  3802.     if (isClass(oop1, floatClass)) {
  3803.       farg1 = floatOOPValue(oop1);
  3804.       setStackTop(floatNew(sqrt(farg1)));
  3805.       return (false);
  3806.     }
  3807.     unPop(1);
  3808.     return (true);
  3809.  
  3810.   /* >>>>>> 167: HOLE <<<<<< */
  3811.  
  3812.   case 168:            /* ceiling */
  3813.   case 169:            /* floor */
  3814.     oop1 = popOOP();
  3815.     if (isClass(oop1, floatClass)) {
  3816.       farg1 = floatOOPValue(oop1);
  3817.       switch (primitive) {
  3818.       case 168: pushInt((long)ceil(farg1));    return (false);
  3819.       case 169: pushInt((long)floor(farg1));    return (false);
  3820. #ifdef why_use_zero
  3821.       case 168: pushInt(0 + (long)ceil(farg1));    return (false);
  3822.       case 169: pushInt(0 + (long)floor(farg1));return (false);
  3823. #endif
  3824.       }
  3825.     }
  3826.     unPop(1);
  3827.     return (true);
  3828.  
  3829.  
  3830.   case 171:            /* truncateTo: aNumber the next multiple of aNumber nearest the receiver towards zero */
  3831.   case 172:            /* rounded -- integer nearest the receiver */
  3832.   case 173:            /* roundTo: aNumber -- multiple of aNumber nearest self */
  3833.   case 174:            /* degreesToRadians */
  3834.   case 175:            /* radiansToDegrees */
  3835.  
  3836.  
  3837.   case 176:            /* sin */
  3838.   case 177:            /* cos */
  3839.   case 178:            /* tan */
  3840.   case 179:            /* arcSin */
  3841.   case 180:            /* arcCos */
  3842.   case 181:            /* arcTan */
  3843.     oop1 = stackTop();
  3844.     if (isClass(oop1, floatClass)) {
  3845.       farg1 = floatOOPValue(oop1);
  3846.       switch (primitive) {
  3847.       case 176: setStackTop(floatNew(sin(farg1)));    return (false);
  3848.       case 177: setStackTop(floatNew(cos(farg1)));    return (false);
  3849.       case 178: setStackTop(floatNew(tan(farg1)));    return (false);
  3850.       case 179: setStackTop(floatNew(asin(farg1)));    return (false);
  3851.       case 180: setStackTop(floatNew(acos(farg1)));    return (false);
  3852.       case 181: setStackTop(floatNew(atan(farg1)));    return (false);
  3853.       }
  3854.     }
  3855.     return (true);
  3856.  
  3857.   case 230:            /* SystemDictionary monitor: aBoolean */
  3858.     oop1 = popOOP();
  3859. #ifdef USE_MONCONTROL    
  3860.     if (oop1 == trueOOP) {
  3861.       moncontrol(1);
  3862.     } else {
  3863.       moncontrol(0);
  3864.     }
  3865. #endif /* USE_MONCONTROL */
  3866.     return (false);
  3867.  
  3868.  
  3869.   case 231:            /* SystemDictionary byteCodeCounter */
  3870.     setStackTopInt(byteCodeCounter);
  3871.     return (false);
  3872.  
  3873. #ifdef old_code /* Thu Jun  6 15:32:40 1991 */
  3874. /**/  case 231:            /* SystemDictionary gcMessage: aBoolean */
  3875. /**/    oop2 = popOOP();
  3876. /**/    oop1 = popOOP();
  3877. /**/    pushBoolean(gcMessage);    /* returned value is old value */
  3878. /**/    gcMessage = (oop2 == trueOOP);
  3879. /**/    return (false);
  3880. #endif /* old_code Thu Jun  6 15:32:40 1991 */
  3881.  
  3882.   case 232:            /* SystemDictionary debug */
  3883.     debug();            /* used to allow dbx to stop based on
  3884.                  * Smalltalk execution paths.
  3885.                  */
  3886.     return (false);
  3887.  
  3888. #ifdef old_code /* Thu Jun  6 15:31:54 1991 */
  3889. /**/  case 233:            /* SystemDictionary verboseTrace: aBoolean */
  3890. /**/    oop1 = popOOP();
  3891. /**/    verboseExecTracing = (oop1 == trueOOP);
  3892. /**/    return (false);
  3893. #endif /* old_code Thu Jun  6 15:31:54 1991 */
  3894.     
  3895.   case 235:            /* Behavior compileString: aString */
  3896.     oop2 = popOOP();
  3897.     oop1 = popOOP();
  3898.     if (isClass(oop2, stringClass)) {
  3899.       exportSP();
  3900.       initLexer(true);
  3901.       pushSmalltalkString(oop2);
  3902.       setCompilationClass(oop1);
  3903.       yyparse();
  3904.       popStream(false);        /* don't close a String! */
  3905.       importSP();
  3906.       pushOOP(latestCompiledMethod);
  3907.       return (false);
  3908.     }
  3909.     unPop(2);
  3910.     return (true);
  3911.  
  3912.   case 236:            /* Behavior compileString: aString
  3913.                             ifError: aBlock */
  3914.     oop3 = popOOP();
  3915.     oop2 = popOOP();
  3916.     oop1 = popOOP();
  3917.     if (isClass(oop2, stringClass) && isClass(oop3, blockContextClass)) {
  3918.       Boolean    oldReportErrors = reportErrors;
  3919.  
  3920.       if (oldReportErrors) {
  3921.     /* only clear out these guys on first transition */
  3922.     firstErrorStr = firstErrorFile = NULL;
  3923.       }
  3924.       reportErrors = false;
  3925.       exportSP();
  3926.       initLexer(true);
  3927.       pushSmalltalkString(oop2);
  3928.       setCompilationClass(oop1);
  3929.       yyparse();
  3930.       popStream(false);        /* don't close a String! */
  3931.       importSP();
  3932.       if (firstErrorStr != NULL) {
  3933.     pushOOP(oop3);        /* block context */
  3934.     if (firstErrorFile != NULL) {
  3935.       pushOOP(stringNew(firstErrorFile));
  3936.       free(firstErrorFile);
  3937.     } else {
  3938.       pushOOP(nil);
  3939.     }
  3940.     pushInt(firstErrorLine);
  3941.     pushOOP(stringNew(firstErrorStr));
  3942.     free(firstErrorStr);
  3943.     firstErrorStr = firstErrorFile = NULL;
  3944.     sendBlockValue(3);
  3945.       } else {
  3946.     pushOOP(latestCompiledMethod);
  3947.       }
  3948.       reportErrors = oldReportErrors;
  3949.       return (false);
  3950.     }
  3951.     unPop(3);
  3952.     return (true);
  3953.  
  3954.  
  3955.  
  3956.  
  3957.   case 240:            /* SysFile class openFile: filename for: read-or-write */
  3958.     return (true);
  3959.  
  3960.   case 241:            /* SysFile close */
  3961.     return (true);
  3962.  
  3963.   case 242:            /* SysFile next */
  3964.     return (true);
  3965.  
  3966.   case 243:            /* SysFile nextPut: aCharOrByte */
  3967.     return (true);
  3968.  
  3969.   case 244:            /* SysFile atEnd */
  3970.     return (true);
  3971.  
  3972.   case 245:            /* SysFile position: anInteger */
  3973.     return (true);
  3974.  
  3975.   case 246:            /* SysFile size */
  3976.     return (true);
  3977.  
  3978.   case 247:            /* FileStream fileIn */
  3979.     oop1 = stackTop();
  3980.     fileStream = (FileStream)oopToObj(oop1);
  3981.     fileOOP = fileStream->file;
  3982.     file = (FILE *)cObjectValue(fileOOP);
  3983.     fileName = toCString(fileStream->name);
  3984.     if (access(fileName, 4) == 0) {
  3985.       exportSP();
  3986.       initLexer(false);
  3987.       pushUNIXFile(file, fileName);
  3988.       yyparse();
  3989.       popStream(false);        /* we didn't open it, so we don't close it */
  3990.       importSP();
  3991.       return (false);
  3992.     }
  3993.     free(fileName);
  3994.     return (true);
  3995.  
  3996.   case 248:            /* FileStream fileInLine: lineNum
  3997.                  *            fileName: aString
  3998.                  *          at: charPosInt
  3999.                  */
  4000.     
  4001.     oop4 = popOOP();
  4002.     oop3 = popOOP();
  4003.     oop2 = popOOP();
  4004.     oop1 = stackTop();
  4005.     fileStream = (FileStream)oopToObj(oop1);
  4006.     fileOOP = fileStream->file;
  4007.     file = (FILE *)cObjectValue(fileOOP);
  4008.     fileName = toCString(fileStream->name);
  4009.     realFileName = nil;
  4010.     if (access(fileName, 4) == 0) {
  4011.       if (isInt(oop2)
  4012.       && (isNil(oop3) || (isClass(oop3, stringClass) && isInt(oop4)))) {
  4013.     arg2 = toInt(oop2);
  4014.     if (!isNil(oop3)) {
  4015.       arg4 = toInt(oop4);
  4016.       realFileName = toCString(oop3);
  4017.     } else {
  4018.       arg4 = 0;
  4019.     }
  4020.  
  4021.     exportSP();
  4022.     initLexer(false);
  4023.     pushUNIXFile(file, fileName);
  4024.     setStreamInfo(arg2, realFileName, arg4);
  4025.     yyparse();
  4026.     popStream(false);        /* we didn't open it, so we don't close it */
  4027.     importSP();
  4028.     return (false);
  4029.       }
  4030.     }
  4031.     free(fileName);
  4032.     if (realFileName) {
  4033.       free(realFileName);
  4034.     }
  4035.     unPop(3);
  4036.     return (true);
  4037.  
  4038.   case 249:            /* Behavior makeDescriptorFor: funcNameString
  4039.                             returning: returnTypeSymbol
  4040.                         withArgs: argsArray */
  4041.     oop4 = popOOP();
  4042.     oop3 = popOOP();
  4043.     oop2 = popOOP();
  4044.     oop1 = popOOP();
  4045.     if (isClass(oop2, stringClass)
  4046.     && (isClass(oop3, symbolClass) || isClass(oop3, cTypeClass))
  4047.     && (isClass(oop4, arrayClass)
  4048.         || isClass(oop4, undefinedObjectClass))) {
  4049.       pushOOP(makeDescriptor(oop2, oop3, oop4));
  4050.       return (false);
  4051.     }
  4052.     unPop(4);
  4053.     return (true);
  4054.  
  4055.   case 250:            /* Object snapshot */
  4056.     saveToFile(defaultImageName);
  4057.     return (false);
  4058.  
  4059.   case 251:            /* Object snapshot: aString */
  4060.     oop2 = popOOP();
  4061.     if (isClass(oop2, stringClass)) {
  4062.       fileName = toCString(oop2);
  4063.       saveToFile(fileName);
  4064.       free(fileName);
  4065.       return (false);
  4066.     }
  4067.     unPop(1);
  4068.     return (true);
  4069.     
  4070.   case 252:            /* Object basicPrint */
  4071.     printf("Object: ");
  4072.     printObject(stackTop());
  4073.     printf("\n");
  4074.     return (false);
  4075.  
  4076.     /* 253 open */
  4077.  
  4078.  
  4079.   case 254:            /* FileStream>>IO primitive, variadic */
  4080.     for (i = numArgs; --i >= 0; ) {
  4081.       oopVec[i] = popOOP();
  4082.     }
  4083.     oop1 = stackTop();
  4084.     if (isInt(oopVec[0])) {
  4085.       failed = false;
  4086.       arg1 = toInt(oopVec[0]);
  4087.       if (arg1 == ENUM_INT(openFilePrim) || arg1 == ENUM_INT(popenFilePrim)) {
  4088.     /* open: fileName[1] mode: mode[2] or
  4089.      * popen: command[1] dir: direction[2] */
  4090.     fileName = toCString(oopVec[1]);
  4091.     fileMode = toCString(oopVec[2]);
  4092.     if (arg1 == ENUM_INT(openFilePrim)) {
  4093.       file = fopen((char *)fileName, (char *)fileMode);
  4094.     } else {
  4095. #ifdef VMS
  4096.       file = NULL;        /* VMS has no popen! */
  4097. #else
  4098.       file = popen((char *)fileName, (char *)fileMode);
  4099. #endif
  4100.     }
  4101.     if (file == NULL) {
  4102. #ifdef old_code /* Sun Sep 22 09:36:23 1991 */
  4103. /**/      errorf("Failed to open %s named '%s'",
  4104. /**/         (ENUM_INT(openFilePrim) == arg1) ? "file" : "pipe",
  4105. /**/         fileName);
  4106. #endif /* old_code Sun Sep 22 09:36:23 1991 */
  4107.       free(fileName);
  4108.       free(fileMode);
  4109.       failed = true;
  4110.       break;
  4111.     }
  4112.       
  4113.     fileOOP = cObjectNew(file);
  4114.     setFileStreamFile(oop1, fileOOP, oopVec[1]);
  4115.     free(fileName);
  4116.     free(fileMode);
  4117.     return (false);
  4118.       } else {
  4119.     fileStream = (FileStream)oopToObj(oop1);
  4120.     fileOOP = fileStream->file;
  4121.     file = (FILE *)cObjectValue(fileOOP);
  4122.     switch (arg1) {
  4123.  
  4124.     case closeFilePrim:    /* FileStream close */
  4125.       fclose(file);
  4126.       return (false);
  4127.     
  4128.     case getCharPrim:    /* FileStream next */
  4129.       ch = getc(file);
  4130.       if (ch == EOF) {    /* cause nil to be returned */
  4131.         failed = true;
  4132.         break;
  4133.       } else {
  4134.         setStackTop(charOOPAt(ch));
  4135.         return (false);
  4136.       }
  4137.       
  4138.     case putCharPrim:    /* FileStream nextPut: aChar */
  4139.       if (isClass(oopVec[1], charClass)) {
  4140.         ch = charOOPValue(oopVec[1]);
  4141.         fputc(ch, file);
  4142.         return (false);
  4143.       } else {
  4144.         failed = true;
  4145.         break;
  4146.       }
  4147.  
  4148.     case seekPrim:        /* FileStream position: position */
  4149.       fseek(file, toInt(oopVec[1]), 0);
  4150.       return (false);
  4151.  
  4152.     case tellPrim:        /* FileStream position */
  4153.       setStackTop(fromInt(ftell(file)));
  4154.       return (false);
  4155.  
  4156.     case eofPrim:        /* FileStream atEnd */ 
  4157.       popOOP();        /* remove self */
  4158.       ch = getc(file);
  4159.       atEof = feof(file);
  4160.       pushBoolean(atEof);
  4161.       ungetc(ch, file);
  4162.       return (false);
  4163.  
  4164.     case sizePrim:
  4165.       if (fstat(fileno(file), &statBuf)) {
  4166.         failed = true;
  4167.         break;
  4168.       } else {
  4169.         setStackTop(fromInt(statBuf.st_size));
  4170.         return (false);
  4171.       }
  4172.  
  4173.     case putCharsPrim:    /* only works for strings currently */
  4174.       fwrite(stringOOPChars(oopVec[1]), numIndexableFields(oopVec[1]), 1, file);
  4175.       return (false);
  4176.  
  4177.     case getCharsPrim:    /* only works for strings */
  4178.       if (isInt(oopVec[1])) {
  4179.         arg2 = toInt(oopVec[1]);
  4180.         stringOOP = newString(arg2);
  4181.         if (fread(stringOOPChars(stringOOP), arg2, 1, file) == 0) {
  4182.           failed = true;
  4183.           break;
  4184.         }
  4185.         setStackTop(stringOOP);
  4186.         return (false);
  4187.       }
  4188.       break;
  4189.     }
  4190.       }
  4191.     }
  4192.  
  4193.     if (failed) {
  4194.       unPop(numArgs);
  4195.     }
  4196.     break;
  4197.  
  4198.   case 255:            /* C callout primitive */
  4199.     inInterpreter = false;
  4200.     exportSP();
  4201.     inCCode = true;
  4202.     if (setjmp(cCalloutJmpBuf) == 0) {
  4203.       invokeCRoutine(numArgs, methodOOP);
  4204.     }
  4205.     inCCode = false;
  4206.     importSP();
  4207.     inInterpreter = true;
  4208.     return (false);
  4209.  
  4210.   default:
  4211.     errorf("Unhandled primitive operation %d", primitive);
  4212.     return (true);
  4213.   }
  4214.  
  4215.   exportSP();
  4216.   return (failed);
  4217.  
  4218. }
  4219.  
  4220. /*
  4221. These are the primitives as defined in the Blue Book.  The ones with numbers
  4222. but without stars are those which are not implemented.
  4223.  
  4224. * 1 +
  4225. * 2 -
  4226. * 3 <
  4227. * 4 >
  4228. * 5 <=
  4229. * 6 >=
  4230. * 7 =
  4231. * 8 ~=
  4232. * 9 *
  4233. * 10 /
  4234. * 11 \\
  4235. * 12 //
  4236. * 13 quo:
  4237. * 14 bitAnd:
  4238. * 15 bitOr:
  4239. * 16 bitXor:
  4240. * 17 bitShift:
  4241.  
  4242. * 40 Smallinteger asFloat
  4243. * 41 Float +
  4244. * 42 Float -
  4245. * 43 Float >
  4246. * 44 Float <
  4247. * 45 Float <=
  4248. * 46 Float >=
  4249. * 47 Float =
  4250. * 48 Float ~=
  4251. * 49 Float *
  4252. * 50 Float /
  4253. * 51 Float truncated
  4254. * 52 Float fractionPart
  4255. * 53 Float exponent
  4256. * 54 Float timesTwoPower:
  4257.  
  4258. * 60 Object at:
  4259.    Object basicAt:
  4260. * 61 Object basicAt:put:
  4261.    Object at:put:
  4262. * 62 Object basicSize
  4263.    Object size
  4264.    String size
  4265.    ArrayedCollection size
  4266. * 63 String at:
  4267.    String basicAt:
  4268. * 64 String basicAt:put:
  4269.    String at:put:
  4270.  
  4271. * 70 Behavior basicNew
  4272.    Behavior new
  4273.    Interval class new
  4274. * 71 Behavior new:
  4275.    Behavior basicNew:
  4276. * 72 Object become:
  4277. * 73 Object instVarAt:
  4278. * 74 Object instVarAt:put:
  4279. * 75 Object asOop
  4280.    Object hash
  4281.    Symbol hash
  4282. * 76 SmallInteger asObject
  4283.    SmallInteger asObjectNoFail
  4284. * 77 Behavior someInstance
  4285. * 78 Object nextInstance
  4286. 79 CompiledMethod class newMethod:header:
  4287. * 80 ContextPart blockCopy:
  4288. * 81 BlockContext value:value:value:
  4289.    BlockContext value:
  4290.    BlockContext value:value:
  4291. * 82 BlockContext valueWithArguments:
  4292. * 83 Object perform:with:with:with:
  4293.    Object perform:with:
  4294.    Object perform:with:with:
  4295.    Object perform:
  4296. * 84 Object perform:withArguments:
  4297.  
  4298. 105 ByteArray primReplaceFrom:to:with:startingAt:
  4299.     ByteArray replaceFrom:to:withString:startingAt:
  4300.     String replaceFrom:to:withByteArray:startingAt:
  4301.     String primReplaceFrom:to:with:startingAt:
  4302.  
  4303. * 110 Character =
  4304.     Object ==
  4305. * 111 Object class
  4306.  
  4307. */
  4308.  
  4309. static OOP getActiveProcess()
  4310. {
  4311.   ProcessorScheduler processor;
  4312.  
  4313.   if (!isNil(switchToProcess)) {
  4314.     return (switchToProcess);
  4315.   } else {
  4316.     processor = (ProcessorScheduler)oopToObj(processorOOP);
  4317.     return (processor->activeProcess);
  4318.   }
  4319. }
  4320.  
  4321. static void addLastLink(semaphoreOOP, processOOP)
  4322. OOP    semaphoreOOP, processOOP;
  4323. {
  4324.   Semaphore    sem;
  4325.   Process    process, lastProcess;
  4326.   OOP        lastProcessOOP;
  4327.  
  4328.  
  4329.   prepareToStore(processOOP, semaphoreOOP);
  4330.   process = (Process)oopToObj(processOOP);
  4331.   process->myList = semaphoreOOP;
  4332.   process->nextLink = nilOOP;
  4333.  
  4334.   sem = (Semaphore)oopToObj(semaphoreOOP);
  4335.   if (isNil(sem->lastLink)) {
  4336.     prepareToStore(semaphoreOOP, processOOP);
  4337.     sem = (Semaphore)oopToObj(semaphoreOOP);
  4338.     sem->firstLink = sem->lastLink = processOOP;
  4339.   } else {
  4340.     lastProcessOOP = sem->lastLink;
  4341.     prepareToStore(lastProcessOOP, processOOP);
  4342.     lastProcess = (Process)oopToObj(lastProcessOOP);
  4343.     lastProcess->nextLink = processOOP;
  4344.     prepareToStore(semaphoreOOP, processOOP);
  4345.     sem = (Semaphore)oopToObj(semaphoreOOP);
  4346.     sem->lastLink = processOOP;
  4347.   }
  4348. }
  4349.  
  4350. syncSignal(semaphoreOOP)
  4351. OOP    semaphoreOOP;
  4352. {
  4353.   Semaphore sem;
  4354.  
  4355.   sem = (Semaphore)oopToObj(semaphoreOOP);
  4356.   if (isEmpty(semaphoreOOP)) {    /* nobody waiting */
  4357.     sem->signals = incrInt(sem->signals);
  4358.   } else {
  4359.     resumeProcess(removeFirstLink(semaphoreOOP));
  4360.   }
  4361. }
  4362.  
  4363. static OOP removeFirstLink(semaphoreOOP)
  4364. OOP    semaphoreOOP;
  4365. {
  4366.   Semaphore    sem;
  4367.   Process    process;
  4368.   OOP        processOOP;
  4369.  
  4370.   sem = (Semaphore)oopToObj(semaphoreOOP);
  4371.   processOOP = sem->firstLink;
  4372.   process = (Process)oopToObj(processOOP);
  4373.  
  4374. /*  prepareToStore(semaphoreOOP, processOOP); */
  4375.   prepareToStore(semaphoreOOP, process->nextLink);
  4376.   sem = (Semaphore)oopToObj(semaphoreOOP);
  4377.   sem->firstLink = process->nextLink;
  4378.   if (isNil(sem->firstLink)) {
  4379.     sem->lastLink = nilOOP;
  4380.   }
  4381.  
  4382.   process->nextLink = nilOOP;
  4383.   process->myList = nilOOP;
  4384.  
  4385.   return (processOOP);
  4386. }
  4387.  
  4388. static void resumeProcess(processOOP)
  4389. OOP    processOOP;
  4390. {
  4391.   OOP        activeOOP;
  4392.   Process    process, active;
  4393.  
  4394.   activeOOP = getActiveProcess();
  4395.   active = (Process)oopToObj(activeOOP);
  4396.   process = (Process)oopToObj(processOOP);
  4397.  
  4398.   if (toInt(process->priority) > toInt(active->priority)) {
  4399.     /*
  4400.      * we're resuming a process with a higher priority, so sleep the
  4401.      * current one and activate the new one
  4402.      */
  4403.     sleepProcess(activeOOP);
  4404.     activateProcess(processOOP);
  4405.   } else {
  4406.     /* this process isn't higher than the active one */
  4407.     sleepProcess(processOOP);
  4408.   }
  4409. }
  4410.  
  4411. static void activateProcess(processOOP)
  4412. OOP    processOOP;
  4413. {
  4414.   switchToProcess = processOOP;
  4415.   exceptFlag = true;
  4416. }
  4417.  
  4418. static void sleepProcess(processOOP)
  4419. OOP    processOOP;
  4420. {
  4421.   Process    process;
  4422.   int        priority;
  4423.   OOP        processLists;
  4424.   OOP        processList;
  4425.  
  4426.   process = (Process)oopToObj(processOOP);
  4427.   priority = toInt(process->priority);
  4428.   processLists = getProcessLists();
  4429.   processList = arrayAt(processLists, priority);
  4430.  
  4431.   /* add process to end of priority queue */
  4432.   addLastLink(processList, processOOP);
  4433. }
  4434.  
  4435.  
  4436. static void suspendActiveProcess()
  4437. {
  4438.   activateProcess(highestPriorityProcess());
  4439. }
  4440.  
  4441.  
  4442. static OOP highestPriorityProcess()
  4443. {
  4444.   OOP        processLists, processList;
  4445.   int        priority;
  4446.  
  4447.   processLists = getProcessLists();
  4448.   priority = numOOPs(oopToObj(processLists));
  4449.   for (; priority > 0 ; priority--) {
  4450.     processList = arrayAt(processLists, priority);
  4451.     if (!isEmpty(processList)) {
  4452.       return (removeFirstLink(processList));
  4453.     }
  4454.   }
  4455.  
  4456.   errorf("No Runnable process!!!");
  4457.   exit(0);            /* maybe return to caller? */
  4458.   /*NOTREACHED*/
  4459. }
  4460.  
  4461. static Boolean isEmpty(processListOOP)
  4462. OOP    processListOOP;
  4463. {
  4464.   Semaphore    processList;
  4465.  
  4466.   processList = (Semaphore)oopToObj(processListOOP);
  4467.   return (isNil(processList->firstLink));
  4468. }
  4469.  
  4470. static OOP getProcessLists()
  4471. {
  4472.   ProcessorScheduler processor;
  4473.  
  4474.   processor = (ProcessorScheduler)oopToObj(processorOOP);
  4475.   return (processor->processLists);
  4476. }
  4477.  
  4478. static OOP semaphoreNew()
  4479. {
  4480.   Semaphore    sem;
  4481.  
  4482.   sem = (Semaphore)instantiate(semaphoreClass);
  4483.   sem->signals = fromInt(0);
  4484.  
  4485.   return (allocOOP(sem));
  4486. }
  4487.  
  4488. /*
  4489.  *    static Boolean *boolAddrIndex(index)
  4490.  *
  4491.  * Description
  4492.  *
  4493.  *    Used to help minimize the number of primitives used to control the
  4494.  *    various debugging flags, this routine maps an index to the address
  4495.  *    of a boolean debug flag, which it returns.
  4496.  *
  4497.  * Inputs
  4498.  *
  4499.  *    index : An integer (0 based) index to the set of debug variables
  4500.  *
  4501.  * Outputs
  4502.  *
  4503.  *    Address of the C debug variable, or NULL on failure.
  4504.  */
  4505. static Boolean *boolAddrIndex(index)
  4506. int    index;
  4507. {
  4508.   switch (index) {
  4509.   case 0: return (&declareTracing);
  4510.   case 1: return (&executionTracing);
  4511.   case 2: return (&verboseExecTracing);
  4512.   case 3: return (&gcMessage);
  4513.   case -1: return (&gcDebug);
  4514.   default:
  4515.     /* index out of range, signal the error */
  4516.     return (NULL);
  4517.  
  4518.   }
  4519. }
  4520.  
  4521.  
  4522. /*
  4523.  *    static void methodHasBlockContext(methodOOP)
  4524.  *
  4525.  * Description
  4526.  *
  4527.  *    Marks a method context has having created a block context.
  4528.  *
  4529.  * Inputs
  4530.  *
  4531.  *    methodOOP: MethodContext OOP to be marked
  4532.  *        
  4533.  *
  4534.  */
  4535. static void methodHasBlockContext(methodOOP)
  4536. OOP    methodOOP;
  4537. {
  4538.   MethodContext methodContext;
  4539.  
  4540.   methodContext = (MethodContext)oopToObj(methodOOP);
  4541.   /* Since trueOOP is in the root set, we don't have to prepare to store it */
  4542.   methodContext->hasBlock = trueOOP;
  4543. }
  4544.  
  4545. void setFileStreamFile(fileStreamOOP, fileOOP, fileNameOOP)
  4546. OOP    fileStreamOOP, fileOOP, fileNameOOP;
  4547. {
  4548.   FileStream    fileStream;
  4549.  
  4550.   fileStream = (FileStream)oopToObj(fileStreamOOP);
  4551.   prepareToStore(fileStreamOOP, fileOOP);
  4552.   fileStream->file = fileOOP;
  4553.   prepareToStore(fileStreamOOP, fileNameOOP);
  4554.   fileStream->name = fileNameOOP;
  4555. }
  4556.  
  4557.  
  4558. /*
  4559.  *    static void sendBlockValue(numArgs)
  4560.  *
  4561.  * Description
  4562.  *
  4563.  *    This is the equivalent of sendMessage, but is for blocks.  The block
  4564.  *    context that is to the the receiver of the "value" message should be
  4565.  *    "numArgs" into the stack.  Temporaries come from the block's method
  4566.  *    context, as does self.  IP is set to the proper
  4567.  *    place within the block's method's byte codes, and SP is set to the top
  4568.  *    of the arguments in the block context, which have been copied out of
  4569.  *    the caller's context.
  4570.  *
  4571.  * Inputs
  4572.  *
  4573.  *    numArgs: 
  4574.  *        The number of arguments sent to the block.
  4575.  *
  4576.  */
  4577. static void sendBlockValue(numArgs)
  4578. int    numArgs;
  4579. {
  4580.   OOP        blockContextOOP, methodContextOOP;
  4581.   BlockContext    blockContext;
  4582.   MethodContext thisContext, methodContext;
  4583.   int        i;
  4584.  
  4585.   /*
  4586.    * although we realized the contexts when we pushed the current oop
  4587.    * onto the stack, we may be sending the block a value from within an inner 
  4588.    * context which has not been realized.  This could hand out a reference to
  4589.    * a fake object which is forbidden
  4590.    */
  4591.   realizeMethodContexts();
  4592.  
  4593.   if (!isNil(thisContextOOP)) {
  4594.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  4595.     /* save old context information */
  4596.     thisContext->ipOffset = fromInt(relativeByteIndex(ip, thisMethod));
  4597.     /* leave sp pointing to receiver, which is replaced on return with value*/
  4598.     thisContext->spOffset = fromInt(sp - numArgs - thisContext->contextStack);
  4599.   }
  4600.  
  4601.   /* prepare the new state */
  4602.   blockContextOOP = stackAt(numArgs);
  4603.   maybeMoveOOP(blockContextOOP); /* make sure we're alive */
  4604.  
  4605.   blockContext = (BlockContext)oopToObj(blockContextOOP);
  4606.   maybeMoveOOP(thisContextOOP);    /* ### not sure if this is needed*/
  4607.   blockContext->caller = thisContextOOP;
  4608.   switch (numArgs) {
  4609.   case 0:    blockContext->selector = valueSymbol; break;
  4610.   case 1:    blockContext->selector = valueColonSymbol; break;
  4611.   case 2:    blockContext->selector = valueColonValueColonSymbol; break;
  4612.   case 3:    blockContext->selector = valueColonValueColonValueColonSymbol; break;
  4613.   default:    blockContext->selector = valueWithArgumentsColonSymbol; break;
  4614.   }
  4615.  
  4616.   /* home is set when the block is created */
  4617.  
  4618.   /* copy numArgs arguments into new context */
  4619.   memcpy(blockContext->contextStack, &sp[-numArgs+1],
  4620.      (numArgs) * sizeof(OOP));
  4621.   for (i = 0; i < numArgs; i++) {
  4622.     maybeMoveOOP(blockContext->contextStack[i]);
  4623.   }
  4624.  
  4625.   sp = &blockContext->contextStack[numArgs-1]; /* start of stack-1 */
  4626.  
  4627.   thisContextOOP = blockContextOOP;
  4628.  
  4629.   methodContextOOP = blockContext->home;
  4630.   methodContext = (MethodContext)oopToObj(methodContextOOP);
  4631.   ip = toInt(blockContext->initialIP) + getMethodByteCodes(methodContext->method);
  4632.   thisMethod = methodContext->method;
  4633.   maybeMoveOOP(thisMethod);
  4634.   temporaries = methodContext->contextStack;
  4635.   self = methodContext->receiver;
  4636.   maybeMoveOOP(self);
  4637. }
  4638.  
  4639. /*
  4640.  *    static char *selectorAsString(selector)
  4641.  *
  4642.  * Description
  4643.  *
  4644.  *    Converts a selector to a C string object
  4645.  *
  4646.  * Inputs
  4647.  *
  4648.  *    selector: A OOP for the selector, a Symbol.
  4649.  *        
  4650.  *
  4651.  * Outputs
  4652.  *
  4653.  *    C string that corresponds to the selector's printed name.
  4654.  */
  4655. static char *selectorAsString(selector)
  4656. OOP    selector;
  4657. {
  4658.   return (symbolAsString(selector));
  4659. }
  4660.  
  4661. /*
  4662.  *    static OOP findMethod(receiverClass, selector)
  4663.  *
  4664.  * Description
  4665.  *
  4666.  *    Scans the methods of "receiverClass" and all its super classes for one
  4667.  *    with selector "selector".  It returns the method if it found, otherwise
  4668.  *    nil is returned.
  4669.  *
  4670.  * Inputs
  4671.  *
  4672.  *    receiverClass:
  4673.  *        The class to begin the search in.  This is normally called from
  4674.  *        the message sending code, so that's why this parameter is
  4675.  *        called receiverClass.
  4676.  *    selector:
  4677.  *        The selector for the method that is being sought.
  4678.  *    methodClassPtr:
  4679.  *        The class that the method was eventually found in.  Passed
  4680.  *        by reference and set when returning.
  4681.  *
  4682.  * Outputs
  4683.  *
  4684.  *    Method for "selector", or nilOOP if not found.  "methodClassPtr" is
  4685.  *    returned as a by-reference parameter.
  4686.  */
  4687. static OOP findMethod(receiverClass, selector, methodClassPtr)
  4688. OOP    receiverClass, selector, *methodClassPtr;
  4689. {
  4690.   OOP        classOOP, methodOOP;
  4691.  
  4692.   for (classOOP = receiverClass; !isNil(classOOP);
  4693.        classOOP = superClass(classOOP)) {
  4694.     methodOOP = findClassMethod(classOOP, selector);
  4695.     if (!isNil(methodOOP)) {
  4696.       *methodClassPtr = classOOP;
  4697.       return (methodOOP);
  4698.     }
  4699.   }
  4700.  
  4701.   *methodClassPtr = undefinedObjectClass; /* probably not used */
  4702.   return (nilOOP);
  4703. }
  4704.  
  4705. /* runs before GC turned on */
  4706. void initProcessSystem()
  4707. {
  4708.   OOP        processLists;
  4709.   int        i;
  4710.   ProcessorScheduler processor;
  4711.   Process    initialProcess;
  4712.   OOP        initialProcessOOP;
  4713.   
  4714.  
  4715.   processLists = arrayNew(NUM_PRIORITIES);
  4716.  
  4717.   for (i = 1; i <= NUM_PRIORITIES; i++) {
  4718.     arrayAtPut(processLists, i, semaphoreNew()); /* ### should be linked list */
  4719.   }
  4720.  
  4721.   initialProcess = (Process)instantiate(processClass);
  4722.   initialProcess->priority = fromInt(4); /* userSchedulingPriority */
  4723.   initialProcessOOP = allocOOP(initialProcess);
  4724.  
  4725.  
  4726.   processor = (ProcessorScheduler)instantiate(processorSchedulerClass);
  4727.   processor->processLists = processLists;
  4728.   processor->activeProcess = initialProcessOOP;
  4729.  
  4730.   processorOOP = allocOOP(processor);
  4731. }
  4732.  
  4733.  
  4734. void initInterpreter()
  4735. {
  4736.   int        i;
  4737.  
  4738.   thisContextOOP = nilOOP;
  4739.   asyncQueueIndex = 0;
  4740.   switchToProcess = nilOOP;
  4741.  
  4742.   for (i = 0; i < NUM_SIGNALS; i++) {
  4743.     semIntHappened[i] = false;
  4744.     semIntVec[i] = nilOOP;
  4745.   }
  4746. }
  4747.  
  4748. void prepareExecutionEnvironment()
  4749. {
  4750.   MethodContext thisContext, newContext;
  4751.   OOP        newContextOOP;
  4752.  
  4753.   abortExecution = false;
  4754.  
  4755. /* dprintf("     prepareExec thisContext is %d, %x\n", isNil(thisContextOOP), thisContextOOP); */
  4756.  
  4757.   if (!isNil(thisContextOOP)) {
  4758. /* dprintf(">>>> entering to non nil environment %8x!\n", thisContextOOP); */
  4759.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  4760.     /* save old context information */
  4761.     thisContext->ipOffset = fromInt(relativeByteIndex(ip, thisMethod));
  4762.     /* leave sp pointing to receiver, which is replaced on return with value*/
  4763.     thisContext->spOffset = fromInt(sp - thisContext->contextStack);
  4764.   }
  4765.  
  4766.   /* now make a dummy context to run with */
  4767.   newContextOOP = allocMethodContext();
  4768.   newContext = (MethodContext)oopToObj(newContextOOP);
  4769.   ip = nil;
  4770.   if (!isFake(thisContextOOP)) {
  4771.     maybeMoveOOP(thisContextOOP);
  4772.   }
  4773. /* dprintf("{{{{ sender for %8x is %8x(prepare)\n", newContext, thisContextOOP); */
  4774.   newContext->sender = thisContextOOP;
  4775.   thisMethod = newContext->method = nilOOP;
  4776.   newContext->methodClass = objectClass; /* no real class */
  4777.   newContext->selector = nilOOP; /* no real selector invoked us */
  4778.   newContext->receiver = nilOOP; /* make self be real (well, nil) */
  4779.   sp = newContext->contextStack - 1;
  4780.  
  4781.   temporaries = newContext->contextStack;
  4782.   self = nilOOP;
  4783.  
  4784.   thisContextOOP = newContextOOP;
  4785.  
  4786.   invalidateMethodCache();
  4787. #ifdef countingByteCodes 
  4788.   initByteCodeCounter();
  4789. #endif
  4790. }
  4791.  
  4792. OOP finishExecutionEnvironment()
  4793. {
  4794.   MethodContext oldContext, thisContext;
  4795.   OOP        oldContextOOP, returnedValue;
  4796.   
  4797.   returnedValue = stackTop();
  4798.   oldContextOOP = thisContextOOP;
  4799.   oldContext = (MethodContext)oopToObj(oldContextOOP);
  4800.   thisContextOOP = oldContext->sender;
  4801.  
  4802.   if (isFake(oldContextOOP)) {
  4803.     deallocMethodContext(oldContextOOP);
  4804.   }
  4805.  
  4806.   if (!isNil(thisContextOOP)) {
  4807. /* dprintf("<<<<< returning to non nil environment %8x!\n", thisContextOOP); */
  4808.     if (!isFake(thisContextOOP)) {
  4809.       maybeMoveOOP(thisContextOOP);
  4810.     }
  4811.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  4812.     /* restore old context information */
  4813.     thisMethod = thisContext->method;
  4814.     maybeMoveOOP(thisMethod);
  4815.     temporaries = thisContext->contextStack;
  4816.     self = thisContext->receiver;
  4817.     maybeMoveOOP(self);
  4818.     ip = toInt(thisContext->ipOffset) + getMethodByteCodes(thisMethod);
  4819.     sp = thisContext->contextStack + toInt(thisContext->spOffset);
  4820.   }
  4821.   return (returnedValue);
  4822. }
  4823.  
  4824. static void invalidateMethodCache()
  4825. {
  4826.   register int    i;
  4827.  
  4828.   cacheHits = cacheMisses = 0;
  4829.  
  4830.   for (i = 0; i < METHOD_CACHE_SIZE; i++) {
  4831.     methodCacheSelectors[i] = primitiveCacheSelectors[i] = nilOOP;
  4832.     methodCacheClasses[i] = primitiveCacheClasses[i] = nilOOP;
  4833.     methodCacheMethods[i] = nilOOP;
  4834.     collide[0] = primitiveCachePrimitives[i] = 0;
  4835.   }
  4836. }
  4837.  
  4838. void updateMethodCache(selectorOOP, classOOP, methodOOP)
  4839. OOP    selectorOOP, classOOP, methodOOP;
  4840. {
  4841.   long        hashIndex;
  4842.  
  4843.   hashIndex = ((long)selectorOOP ^ (long)classOOP) >> 4;
  4844.   hashIndex &= (METHOD_CACHE_SIZE - 1);
  4845.   if (methodCacheSelectors[hashIndex] == selectorOOP &&
  4846.       methodCacheClasses[hashIndex] == classOOP) {
  4847.     methodCacheMethods[hashIndex] = methodOOP;
  4848.   }
  4849. }
  4850.  
  4851. #ifdef countingByteCodes
  4852. initByteCodeCounter()
  4853. {
  4854.   int i;
  4855.  
  4856.   for (i = 0; i < 256; i++) {
  4857.     primitives[i] = byteCodes[i] = 0;
  4858.   }
  4859. }
  4860.  
  4861. printByteCodeCounts()
  4862. {
  4863.   int i;
  4864.  
  4865.   for (i = 0; i < 256; i++) {
  4866.     if (byteCodes[i]) {
  4867.       printf("Byte code %d = %d\n", i, byteCodes[i]);
  4868.     }
  4869.   }
  4870.  
  4871.   printf("\n---> primitives:\n");
  4872.   for (i = 0; i < 256; i++) {
  4873.     if (primitives[i]) {
  4874.       printf("Primitive %d = %d\n", i, primitives[i]);
  4875.     }
  4876.   }
  4877.  
  4878. }
  4879. #endif
  4880.  
  4881.  
  4882. /* #ifdef ACCESSOR_DEBUGGING */
  4883. static int relativeByteIndex(bp, methodOOP)
  4884. Byte    *bp;
  4885. OOP    methodOOP;
  4886. {
  4887.   return (relativeByteIndexInternal(bp, methodOOP));
  4888. }
  4889. /* #endif /* ACCESSOR_DEBUGGING */
  4890.  
  4891. /*
  4892.  *    void moveProcessorRegisters()
  4893.  *
  4894.  * Description
  4895.  *
  4896.  *    Part of the GC flip, copy the root set process.  This ensures that the
  4897.  *    processor registers are pointing to objects in new space.  The term
  4898.  *    "processor registers" refers here to interpreter variables like ip, sp,
  4899.  *    temporaries, etc.
  4900.  *
  4901.  */
  4902. void moveProcessorRegisters()
  4903. {
  4904.   MethodContext thisContext;    /* may be block context, but doesn't matter */
  4905.   MethodContext    methodContext;
  4906.   int        spOffset, ipOffset;
  4907.   OOP        methodContextOOP;
  4908.  
  4909.   if (isFake(thisContextOOP)) {
  4910.     copyFakeContextObjects();
  4911.   } else {
  4912.     /* Right off the top of my head, I can't think why I need to invalidate
  4913.      * the method cache when I do a GC flip */
  4914.     /* invalidateMethodCache(); */
  4915.  
  4916.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  4917.     spOffset = sp - thisContext->contextStack;
  4918.     ipOffset = relativeByteIndex(ip, thisMethod);
  4919.  
  4920.     localMaybeMoveOOP(thisContextOOP);
  4921.     localMaybeMoveOOP(thisMethod);
  4922.  
  4923.     ip = ipOffset + getMethodByteCodes(thisMethod);
  4924.  
  4925.     thisContext = (MethodContext)oopToObj(thisContextOOP);
  4926.     sp = thisContext->contextStack + spOffset;
  4927.  
  4928.     methodContextOOP = getMethodContext(thisContextOOP);
  4929.     localMaybeMoveOOP(methodContextOOP);
  4930.     methodContext = (MethodContext)oopToObj(methodContextOOP);
  4931.  
  4932.     temporaries = methodContext->contextStack;
  4933.     /* self remains valid (doesn't have to be refetched from methodcontext) */
  4934.     localMaybeMoveOOP(self);
  4935.  
  4936.   }
  4937.   moveSemaphoreOOPs();
  4938.  
  4939.   /* added experimentally */
  4940.   localMaybeMoveOOP(processorOOP);
  4941. }
  4942.  
  4943. static void copyFakeContextObjects()
  4944. {
  4945.   MethodContext    methodContext;
  4946.   int        stackDepth, i;
  4947.   OOP        c;
  4948.   
  4949.   methodContext = (MethodContext)oopToObj(thisContextOOP);
  4950.   /* make this regular */
  4951.   methodContext->spOffset = fromInt(sp - methodContext->contextStack);
  4952.  
  4953.   for (c = thisContextOOP; isFake(c); c = methodContext->sender) {
  4954.     methodContext = (MethodContext)oopToObj(c);
  4955.  
  4956.     if (!isFake(methodContext->sender)) {
  4957. /* dprintf("{{{{ moving sender in copy %8x\n", methodContext); */
  4958.       localMaybeMoveOOP(methodContext->sender);
  4959.     }
  4960.  
  4961.     localMaybeMoveOOP(methodContext->method);
  4962.     localMaybeMoveOOP(methodContext->methodClass);
  4963.     if (methodContext->hasBlock != nilOOP) {
  4964.       printf("fake context has a block!!!\n");
  4965.     }
  4966.     localMaybeMoveOOP(methodContext->selector); /* seems wasteful...it's a symbol
  4967.                         * and symbols won't be gc'd */
  4968.     localMaybeMoveOOP(methodContext->receiver);
  4969.     stackDepth = toInt(methodContext->spOffset);
  4970.     for (i = 0; i <= stackDepth; i++) {
  4971.       localMaybeMoveOOP(methodContext->contextStack[i]);
  4972.     }
  4973.   }
  4974.  
  4975.   /* leave things like sp, temporaries alone since we haven't moved our
  4976.    * fake context!
  4977.    */
  4978. }
  4979.  
  4980. /*
  4981.  *    static void moveSemaphoreOOPs()
  4982.  *
  4983.  * Description
  4984.  *
  4985.  *    This routine doesn't really do anything yet.  It's intended purpose is
  4986.  *    to be called during the root set copying part of a GC flip to copy any
  4987.  *    asynchronous semaphores.  However, the async semaphore representation
  4988.  *    is likely not to be in terms of Smalltalk objects for a variety of
  4989.  *    reasons, so the need for this routine may never materialize.
  4990.  *
  4991.  */
  4992. static void moveSemaphoreOOPs()
  4993. {
  4994.   int        i;
  4995.   IntState    oldSigMask;
  4996.  
  4997.   oldSigMask = disableInterrupts(); /* block out everything! */
  4998.   /* ### this needs to be changed; async signals shouldn't be oops! */
  4999.   for (i = 0; i < asyncQueueIndex; i++) {
  5000.     moveOOP(queuedAsyncSignals[i]);
  5001.   }
  5002.   enableInterrupts(oldSigMask);
  5003. }
  5004.  
  5005. /*
  5006.  *    void initSignals()
  5007.  *
  5008.  * Description
  5009.  *
  5010.  *    Trap the signals that we care about, basically SIGBUS and SIGSEGV.
  5011.  *    These are sent to the back trace routine so we can at least have some
  5012.  *    idea of where we were when we died.
  5013.  *
  5014.  */
  5015. void initSignals()
  5016. {
  5017.   signal(SIGBUS, interruptHandler);
  5018.   signal(SIGSEGV, interruptHandler);
  5019.  
  5020.   signal(SIGINT, stopExecuting);
  5021. }
  5022.  
  5023.  
  5024. /*
  5025.  *    static signalType stopExecuting(sig)
  5026.  *
  5027.  * Description
  5028.  *
  5029.  *    Sets flags so that the interpreter starts returning immediately
  5030.  *    from whatever byte codes it's executing.  It returns via normal method
  5031.  *    returns, so that the world is in a consistent state when it's done.
  5032.  *
  5033.  * Inputs
  5034.  *
  5035.  *    sig   : signal that caused the interrupt (typically ^C), or 0, which
  5036.  *        comes from a call from within the system.
  5037.  *
  5038.  */
  5039. static signalType stopExecuting(sig)
  5040. {
  5041.   if (sig) {
  5042.     printf("\nInterrupt!\n");
  5043.   }
  5044.  
  5045.   abortExecution = true;
  5046.   exceptFlag = true;
  5047.   if (inCCode) {
  5048.     longjmp(cCalloutJmpBuf, 1);    /* throw out from C code */
  5049.   }
  5050. }
  5051.  
  5052.  
  5053. static signalType timeoutHandler(sig)
  5054. int sig;
  5055. {
  5056.   signalTimeoutSemaphore = true;
  5057.   exceptFlag = true;
  5058. }
  5059.  
  5060. static signalType semIntHandler(sig)
  5061. int sig;
  5062. {
  5063.   semIntHappened[sig] = true;
  5064.   semIntFlag = true;
  5065.   exceptFlag = true;
  5066. }
  5067.  
  5068.  
  5069. /*
  5070.  *    static signalType interruptHandler(sig)
  5071.  *
  5072.  * Description
  5073.  *
  5074.  *    Called to handle serious problems, such as segmentation violation.
  5075.  *    Tries to show a method invocation backtrace if possibly, otherwise
  5076.  *    tries to show where the system was in the file it was procesing when
  5077.  *    the error occurred.
  5078.  *
  5079.  * Inputs
  5080.  *
  5081.  *    sig   : Signal number, an integer
  5082.  *
  5083.  * Outputs
  5084.  *
  5085.  *    not used.  Always exits from Smalltalk.
  5086.  */
  5087. static signalType interruptHandler(sig)
  5088. int    sig;
  5089. {
  5090.   switch (sig) {
  5091.   case SIGBUS:
  5092.     errorf("Bus Error");
  5093.     break;
  5094.  
  5095.   case SIGSEGV:
  5096.     errorf("Segmentation violation");
  5097.     break;
  5098.     
  5099.   default:
  5100.     errorf("Unknown signal caught: %d", sig);
  5101.   }
  5102.  
  5103.   if (makeCoreFile) {
  5104.     kill(getpid(), SIGQUIT);    /* die with a core dump */
  5105.   }
  5106.  
  5107.   if (inInterpreter) {
  5108.     showBacktrace();
  5109.   } else {
  5110.     errorf("Error occurred while not in byte code interpreter!!");
  5111.   }
  5112.  
  5113.   exit(1);
  5114. }
  5115.  
  5116. static void showBacktrace()
  5117. {
  5118.   OOP        context, receiver, receiverClass;
  5119.   MethodContext methodContext, nextContext;
  5120.   BlockContext    blockContext;
  5121.  
  5122. /* printf("In showbacktrace\n"); */
  5123.   for (context = thisContextOOP; !isNil(context);
  5124.        context = nextContext->sender) {
  5125.     if (!isRealOOP(context)
  5126.     && (context->flags != F_FAKE)) { /* where F_FAKE is set, it's always
  5127.                       * exactly that...no other bits
  5128.                       * are ever set in a fake oop */
  5129.       printf("Context stack corrupted!\n");
  5130.       break;
  5131.     }
  5132.     if (isBlockContext(context)) {
  5133. /* printf("In block context\n"); */
  5134.       blockContext = (BlockContext)oopToObj(context);
  5135.       methodContext = (MethodContext)oopToObj(blockContext->home);
  5136. /* printf("after method context\n"); */
  5137.       receiver = methodContext->receiver;
  5138.       if (isInt(receiver)) {
  5139.     receiverClass = integerClass;
  5140.       } else {
  5141.     if (!isRealOOP(receiver)) {
  5142.       printf("Context stack corrupted!\n");
  5143.       break;
  5144.     }
  5145.     receiverClass = oopClass(receiver);
  5146.       }
  5147.       printf("[] in ");
  5148.       printObject(methodContext->methodClass);
  5149.       /* printObject(receiverClass);*/
  5150.       nextContext = (MethodContext)blockContext;
  5151.     } else {
  5152. /* printf("a method context\n"); */
  5153.       methodContext = (MethodContext)oopToObj(context);
  5154.  
  5155.       if (!isRealOOP(methodContext->selector)) {
  5156.     printf("Context stack corrupted!\n");
  5157.     break;
  5158.       }
  5159.       
  5160.       receiver = methodContext->receiver;
  5161.       if (isInt(receiver)) {
  5162.     receiverClass = integerClass;
  5163.       } else {
  5164.     if (!isRealOOP(receiver)) {
  5165.       printf("Context stack corrupted!\n");
  5166.       break;
  5167.     }
  5168.     receiverClass = oopClass(receiver);
  5169.       }
  5170.       printObject(receiverClass);
  5171.       if (receiverClass != methodContext->methodClass) {
  5172.     printf("(");
  5173.     printObject(methodContext->methodClass);
  5174.     printf(")");
  5175.       }
  5176.       nextContext = methodContext;
  5177.     }
  5178.     printf(">>");
  5179.     printObject(methodContext->selector);
  5180.     printf("\n");
  5181.   }
  5182.  
  5183. }
  5184.  
  5185. static Boolean isRealOOP(oop)
  5186. OOP oop;
  5187. {
  5188.   return (oop >= oopTable && oop < &oopTable[TOTAL_OOP_TABLE_SLOTS]);
  5189. }
  5190.  
  5191.  
  5192. checkStack(oop)
  5193. OOP    oop;
  5194. {
  5195.   MethodContext    methodContext;
  5196.   int    depth;
  5197.   methodContext = (MethodContext)oopToObj(thisContextOOP);
  5198.  
  5199.   if ((depth = sp - methodContext->contextStack) >= CONTEXT_STACK_SIZE - 1) {
  5200.     printf("##### stack at %d, oop = %8x\n", depth, oop);
  5201.     debug();
  5202.   }
  5203. }
  5204.